diff --git a/test/local_packs/S/SomeVendor.RteTest.pdsc b/test/local_packs/S/SomeVendor.RteTest.pdsc index 904c1552d..754388acc 100644 --- a/test/local_packs/S/SomeVendor.RteTest.pdsc +++ b/test/local_packs/S/SomeVendor.RteTest.pdsc @@ -30,6 +30,61 @@ + + + Test bundle one + https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#Component_Bundle + + Bundle One, component G0, version differs from bundle + + + + + + + Test bundle two + https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#element_bundle + + Bundle Two, component G, version differs from bundle + + + + + + + Component G without bundle, but the same class and group as in bundle + + + + + + + Test bundle one + https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#Component_Bundle + + Bundle One, component G0, version differs from bundle + + + + + + + Test bundle two + https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#element_bundle + + Bundle Two, component G, version differs from bundle + + + + + + + Component G without bundle, but the same class and group as in bundle + + + + + diff --git a/tools/projmgr/src/ProjMgrWorker.cpp b/tools/projmgr/src/ProjMgrWorker.cpp index f94624b5c..f92121a7f 100644 --- a/tools/projmgr/src/ProjMgrWorker.cpp +++ b/tools/projmgr/src/ProjMgrWorker.cpp @@ -1911,6 +1911,7 @@ bool ProjMgrWorker::ProcessComponents(ContextItem& context) { } map> processedComponents; + map>> processedBundles; for (auto& [item, layer] : context.componentRequirements) { if (item.component.empty()) { continue; @@ -1937,10 +1938,20 @@ bool ProjMgrWorker::ProcessComponents(ContextItem& context) { return pair.first.compare(aggCompId) == 0; }); if (itr != processedComponents.end()) { - // multiple variant of the same component found + // multiple variants of the same component found error = true; } + string bundleId = matchedComponentInstance->GetCbundleName(); + if (!bundleId.empty()) { + string classId = matchedComponentInstance->GetCclassName(); + processedBundles[classId][bundleId].push_back(item.component); + if (processedBundles[classId].size() > 1) { + // multiple bundles of the same class found (without considering Cvendor) + error = true; + } + } + // Set layer's rtePath attribute if (!layer.empty()) { error_code ec; @@ -2022,13 +2033,34 @@ bool ProjMgrWorker::ProcessComponents(ContextItem& context) { // check if same component variants are specified multiple times for (const auto& pair : processedComponents) { if (pair.second.size() > 1) { - string errMsg = "multiple variants of the same component are specified:"; + string errMsg = "multiple Cvariants of the same component are mutually exclusive:"; for (const auto& comp : pair.second) { errMsg += ("\n - " + comp); } ProjMgrLogger::Get().Error(errMsg, context.name); } } + // check if different bundles are specified for the same class + string errMsg; + bool hasConflict = false; + for (const auto& [classId, bundleMap] : processedBundles) { + if (bundleMap.size() > 1) { + if (!hasConflict) { + errMsg = "components in the same Cclass must belong to the same Cbundle."; + hasConflict = true; + } + errMsg += "\nConflicting Cbundle in Cclass '" + classId + "':"; + for (const auto& [bundleId, components] : bundleMap) { + errMsg += "\n - '" + bundleId + "' component(s):"; + for (const auto& comp : components) { + errMsg += "\n - " + comp; + } + } + } + } + if (hasConflict) { + ProjMgrLogger::Get().Error(errMsg, context.name); + } } // Add required components into RTE diff --git a/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject1/testProject1.cproject.yml b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject1/testProject1.cproject.yml new file mode 100644 index 000000000..6e1a5be49 --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject1/testProject1.cproject.yml @@ -0,0 +1,8 @@ +project: + components: + - component: Startup + - component: RteTest:CORE + - component: ARM::RteTestBundle:G0 + - component: ARM::RteTestBundle&BundleOne:G0 + - component: SomeVendor::RteTestBundle:G0 + - component: SomeVendor::RteTestBundle&BundleOne:G0 diff --git a/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject2/testProject2.cproject.yml b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject2/testProject2.cproject.yml new file mode 100644 index 000000000..41f30489a --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/TestProject2/testProject2.cproject.yml @@ -0,0 +1,11 @@ +project: + components: + - component: Startup + - component: CORE + # Cclass RteTestBundle + - component: ARM::RteTestBundle&BundleOne:G0 + - component: ARM::RteTestBundle&BundleOne:G1 + - component: SomeVendor::RteTestBundle&BundleTwo:G0 + # Cclass RteTestBundle2 + - component: SomeVendor::RteTestBundle2&BundleOne:G0 + - component: SomeVendor::RteTestBundle2&BundleTwo:G0 diff --git a/tools/projmgr/test/data/TestSolution/MultiBundleComponent/multiBundleComponent.csolution.yml b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/multiBundleComponent.csolution.yml new file mode 100644 index 000000000..7db5e2aee --- /dev/null +++ b/tools/projmgr/test/data/TestSolution/MultiBundleComponent/multiBundleComponent.csolution.yml @@ -0,0 +1,17 @@ +solution: + target-types: + - type: CM0 + device: RteTest_ARMCM0 + + build-types: + - type: Debug + compiler: AC6 + + packs: + - pack: ARM::RteTest + - pack: ARM::RteTest_DFP@0.2.0 + - pack: SomeVendor::RteTest@0.0.1 + + projects: + - project: ./TestProject1/testProject1.cproject.yml + - project: ./TestProject2/testProject2.cproject.yml diff --git a/tools/projmgr/test/src/ProjMgrUnitTests.cpp b/tools/projmgr/test/src/ProjMgrUnitTests.cpp index 3217ff372..e5500a04d 100644 --- a/tools/projmgr/test/src/ProjMgrUnitTests.cpp +++ b/tools/projmgr/test/src/ProjMgrUnitTests.cpp @@ -6458,7 +6458,37 @@ TEST_F(ProjMgrUnitTests, RunProjMgr_MultiVariantComponent) { auto errMsg = streamRedirect.GetErrorString(); EXPECT_NE(string::npos, - errMsg.find("multiple variants of the same component are specified:\n - Device:Test variant\n - Device:Test variant&Variant name")); + errMsg.find("multiple Cvariants of the same component are mutually exclusive:\n - Device:Test variant\n - Device:Test variant&Variant name")); +} + +TEST_F(ProjMgrUnitTests, RunProjMgr_MultiBundleComponent) { + StdStreamRedirect streamRedirect; + char* argv[8]; + string csolutionFile = testinput_folder + "/TestSolution/MultiBundleComponent/multiBundleComponent.csolution.yml"; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolutionFile.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)testoutput_folder.c_str(); + argv[6] = (char*)"--context"; + + argv[7] = (char*)"testProject1"; + EXPECT_EQ(0, RunProjMgr(8, argv, m_envp)); + auto errMsg = streamRedirect.GetErrorString(); + EXPECT_EQ(string::npos, errMsg.find("components from multiple bundles are specified:")); + streamRedirect.ClearStringStreams(); + + argv[7] = (char*)"testProject2"; + EXPECT_EQ(1, RunProjMgr(8, argv, m_envp)); + errMsg = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errMsg.find("components in the same Cclass must belong to the same Cbundle.")); + EXPECT_NE(string::npos, errMsg.find("Conflicting Cbundle in Cclass 'RteTestBundle':")); + EXPECT_NE(string::npos, errMsg.find(" - 'BundleOne' component(s):")); + EXPECT_NE(string::npos, errMsg.find(" - ARM::RteTestBundle&BundleOne:G0")); + EXPECT_NE(string::npos, errMsg.find("- ARM::RteTestBundle&BundleOne:G1")); + EXPECT_NE(string::npos, errMsg.find(" - 'BundleTwo' component(s):")); + EXPECT_NE(string::npos, errMsg.find(" - SomeVendor::RteTestBundle&BundleTwo:G0")); + EXPECT_NE(string::npos, errMsg.find("Conflicting Cbundle in Cclass 'RteTestBundle2':")); } TEST_F(ProjMgrUnitTests, RunProjMgr_ListPacks_ContextSet) { @@ -7400,37 +7430,26 @@ TEST_F(ProjMgrUnitTests, TargetSetDependencies) { } TEST_F(ProjMgrUnitTests, DuplicateComponents) { - StdStreamRedirect streamRedirect; - - const string csolution = testinput_folder + "/TestSolution/DuplicateComponents/duplicateComponents.csolution.yml"; - - char* argv[9]; - argv[1] = (char*)"convert"; - argv[2] = (char*)"--solution"; - argv[3] = (char*)csolution.c_str(); - argv[4] = (char*)"-o"; - argv[5] = (char*)testoutput_folder.c_str(); - argv[6] = (char*)"--context"; - argv[7] = (char*)"duplicateComponents_cproject"; - argv[8] = (char*)"--no-check-schema"; - - EXPECT_EQ(1, RunProjMgr(8, argv, m_envp)); - auto errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find("error csolution: conflict: component 'RteTest:CORE' is listed multiple times")); - - argv[7] = (char*)"duplicateComponents_clayer"; - EXPECT_EQ(1, RunProjMgr(8, argv, m_envp)); - errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find("error csolution: conflict: component 'RteTest:CORE' is listed multiple times")); - - // Run with "--no-check-schema" - argv[7] = (char*)"duplicateComponents_cproject"; - EXPECT_EQ(1, RunProjMgr(9, argv, m_envp)); - errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find("error csolution: conflict: component 'RteTest:CORE' is listed multiple times")); - - argv[7] = (char*)"duplicateComponents_clayer"; - EXPECT_EQ(1, RunProjMgr(9, argv, m_envp)); - errStr = streamRedirect.GetErrorString(); - EXPECT_NE(string::npos, errStr.find("error csolution: conflict: component 'RteTest:CORE' is listed multiple times")); + StdStreamRedirect streamRedirect; + const string csolution = testinput_folder + "/TestSolution/DuplicateComponents/duplicateComponents.csolution.yml"; + char* argv[9]; + argv[1] = (char*)"convert"; + argv[2] = (char*)"--solution"; + argv[3] = (char*)csolution.c_str(); + argv[4] = (char*)"-o"; + argv[5] = (char*)testoutput_folder.c_str(); + argv[6] = (char*)"--context"; + argv[8] = (char*)"--no-check-schema"; + + const char* contexts[] = { "duplicateComponents_cproject", "duplicateComponents_clayer" }; + int argCounts[] = { 8, 9 }; // without/with --no-check-schema + for (int argCount : argCounts) { + for (const char* context : contexts) { + argv[7] = (char*)context; + EXPECT_EQ(1, RunProjMgr(argCount, argv, m_envp)); + auto errStr = streamRedirect.GetErrorString(); + EXPECT_NE(string::npos, errStr.find("error csolution: conflict: component 'RteTest:CORE' is listed multiple times")); + streamRedirect.ClearStringStreams(); + } + } }