Skip to content
Merged
55 changes: 55 additions & 0 deletions test/local_packs/S/SomeVendor.RteTest.pdsc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,61 @@
<file category="sourceC" name="PreInclude/MyLocalPreInclude.c" />
</files>
</component>

<bundle Cbundle="BundleOne" Cclass="RteTestBundle" Cversion="1.1.0" Cvendor="SomeVendor">
<description>Test bundle one</description>
<doc>https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#Component_Bundle</doc>
<component Cgroup="G0" Cversion="1.0.0" >
<description>Bundle One, component G0, version differs from bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/cp_PackTutorial.html"/>
</files>
</component>
</bundle>
<bundle Cbundle="BundleTwo" Cclass="RteTestBundle" Cversion="1.2.0" Cvendor="SomeVendor">
<description>Test bundle two</description>
<doc>https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#element_bundle</doc>
<component Cgroup="G0" Cversion="2.0.0" >
<description>Bundle Two, component G, version differs from bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_conditions_pg.html"/>
</files>
</component>
</bundle>
<component Cclass="RteTestBundle" Cgroup="G0" Cversion="0.9.0">
<description>Component G without bundle, but the same class and group as in bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html"/>
</files>
</component>

<bundle Cbundle="BundleOne" Cclass="RteTestBundle2" Cversion="1.1.0" Cvendor="SomeVendor">
<description>Test bundle one</description>
<doc>https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#Component_Bundle</doc>
<component Cgroup="G0" Cversion="1.0.0" >
<description>Bundle One, component G0, version differs from bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/cp_PackTutorial.html"/>
</files>
</component>
</bundle>
<bundle Cbundle="BundleTwo" Cclass="RteTestBundle2" Cversion="1.2.0" Cvendor="SomeVendor">
<description>Test bundle two</description>
<doc>https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html#element_bundle</doc>
<component Cgroup="G0" Cversion="2.0.0" >
<description>Bundle Two, component G, version differs from bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_conditions_pg.html"/>
</files>
</component>
</bundle>
<component Cclass="RteTestBundle2" Cgroup="G0" Cversion="0.9.0">
<description>Component G without bundle, but the same class and group as in bundle</description>
<files>
<file category="doc" name="https://arm-software.github.io/CMSIS_5/Pack/html/pdsc_components_pg.html"/>
</files>
</component>

</components>

</package>
36 changes: 34 additions & 2 deletions tools/projmgr/src/ProjMgrWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,7 @@ bool ProjMgrWorker::ProcessComponents(ContextItem& context) {
}

map<string, vector<string>> processedComponents;
map<string, map<string, vector<string>>> processedBundles;
for (auto& [item, layer] : context.componentRequirements) {
if (item.component.empty()) {
continue;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
87 changes: 53 additions & 34 deletions tools/projmgr/test/src/ProjMgrUnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
}
}
}
Loading