Browse Source

Merge branch 'feature/allow_multiple_fragment_definitions_for_library_v4.0' into 'master'

Allow multiple mapping fragments to map same library

See merge request idf/esp-idf!4713
Angus Gratton 6 years ago
parent
commit
df0b8db400
3 changed files with 122 additions and 16 deletions
  1. 2 0
      tools/ldgen/fragments.py
  2. 17 16
      tools/ldgen/generation.py
  3. 103 0
      tools/ldgen/test/test_generation.py

+ 2 - 0
tools/ldgen/fragments.py

@@ -279,6 +279,7 @@ class Mapping(Fragment):
     def __init__(self):
         Fragment.__init__(self)
         self.entries = set()
+        self.deprecated = False
 
     def set_key_value(self, key, parse_results):
         if key == "archive":
@@ -382,6 +383,7 @@ class DeprecatedMapping():
             fragment = Mapping()
             fragment.archive = toks[0].archive
             fragment.name = re.sub(r"[^0-9a-zA-Z]+", "_", fragment.archive)
+            fragment.deprecated = True
 
             fragment.entries = set()
             condition_true = False

+ 17 - 16
tools/ldgen/generation.py

@@ -334,8 +334,8 @@ class GenerationModel:
 
         # Generate rules based on mapping fragments
         for mapping in self.mappings.values():
-            mapping_rules = list()
             archive = mapping.archive
+            mapping_rules = all_mapping_rules[archive]
             for (obj, symbol, scheme_name) in mapping.entries:
                 try:
                     if not (obj == Mapping.MAPPING_ALL_OBJECTS and symbol is None and
@@ -345,8 +345,6 @@ class GenerationModel:
                     message = GenerationException.UNDEFINED_REFERENCE + " to scheme '" + scheme_name + "'."
                     raise GenerationException(message, mapping)
 
-            all_mapping_rules[mapping.name] = mapping_rules
-
         # Detect rule conflicts
         for mapping_rules in all_mapping_rules.items():
             self._detect_conflicts(mapping_rules)
@@ -453,21 +451,24 @@ class GenerationModel:
         for fragment in fragment_file.fragments:
             dict_to_append_to = None
 
-            if isinstance(fragment, Scheme):
-                dict_to_append_to = self.schemes
-            elif isinstance(fragment, Sections):
-                dict_to_append_to = self.sections
+            if isinstance(fragment, Mapping) and fragment.deprecated and fragment.name in self.mappings.keys():
+                self.mappings[fragment.name].entries |= fragment.entries
             else:
-                dict_to_append_to = self.mappings
-
-            # Raise exception when the fragment of the same type is already in the stored fragments
-            if fragment.name in dict_to_append_to.keys():
-                stored = dict_to_append_to[fragment.name].path
-                new = fragment.path
-                message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new)
-                raise GenerationException(message)
+                if isinstance(fragment, Scheme):
+                    dict_to_append_to = self.schemes
+                elif isinstance(fragment, Sections):
+                    dict_to_append_to = self.sections
+                else:
+                    dict_to_append_to = self.mappings
+
+                # Raise exception when the fragment of the same type is already in the stored fragments
+                if fragment.name in dict_to_append_to.keys():
+                    stored = dict_to_append_to[fragment.name].path
+                    new = fragment.path
+                    message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new)
+                    raise GenerationException(message)
 
-            dict_to_append_to[fragment.name] = fragment
+                dict_to_append_to[fragment.name] = fragment
 
 
 class TemplateModel:

+ 103 - 0
tools/ldgen/test/test_generation.py

@@ -1246,6 +1246,109 @@ entries:
 
             self.compare_rules(expected, actual)
 
+    def test_rule_generation_multiple_deprecated_mapping_definitions(self):
+        multiple_deprecated_definitions = u"""
+[mapping]
+archive: lib.a
+entries:
+    : PERFORMANCE_LEVEL = 0
+    : PERFORMANCE_LEVEL = 1
+    obj1 (noflash)
+    : PERFORMANCE_LEVEL = 2
+    obj1 (noflash)
+    : PERFORMANCE_LEVEL = 3
+    obj1 (noflash)
+
+[mapping]
+archive: lib.a
+entries:
+    : PERFORMANCE_LEVEL = 1
+    obj1 (noflash) # ignore duplicate definition
+    : PERFORMANCE_LEVEL = 2
+    obj2 (noflash)
+    : PERFORMANCE_LEVEL = 3
+    obj2 (noflash)
+    obj3 (noflash)
+"""
+
+        for perf_level in range(0, 4):
+            self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value(str(perf_level))
+
+            self.model.mappings = {}
+            self.add_fragments(multiple_deprecated_definitions)
+
+            actual = self.model.generate_rules(self.sections_info)
+            expected = self.generate_default_rules()
+
+            if perf_level < 4:
+                for append_no in range(1, perf_level + 1):
+                    flash_text_default = self.get_default("flash_text", expected)
+                    flash_rodata_default = self.get_default("flash_rodata", expected)
+
+                    iram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["text"].entries, "iram0_text")
+                    dram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["rodata"].entries, "dram0_data")
+
+                    flash_text_default.add_exclusion(iram_rule)
+                    flash_rodata_default.add_exclusion(dram_rule)
+
+                    expected["iram0_text"].append(iram_rule)
+                    expected["dram0_data"].append(dram_rule)
+
+            self.compare_rules(expected, actual)
+
+    def test_rule_generation_multiple_mapping_definitions(self):
+        multiple_deprecated_definitions = u"""
+[mapping:base]
+archive: lib.a
+entries:
+    if PERFORMANCE_LEVEL = 1:
+        obj1 (noflash)
+    elif PERFORMANCE_LEVEL = 2:
+        obj1 (noflash)
+    elif PERFORMANCE_LEVEL = 3:
+        obj1 (noflash)
+    else:
+        * (default)
+
+[mapping:extra]
+archive: lib.a
+entries:
+    if PERFORMANCE_LEVEL = 1:
+        obj1 (noflash) # ignore duplicate definition
+    elif PERFORMANCE_LEVEL = 2:
+        obj2 (noflash)
+    elif PERFORMANCE_LEVEL = 3:
+        obj2 (noflash)
+        obj3 (noflash)
+    else:
+        * (default)
+"""
+
+        for perf_level in range(0, 4):
+            self.sdkconfig.config.syms["PERFORMANCE_LEVEL"].set_value(str(perf_level))
+
+            self.model.mappings = {}
+            self.add_fragments(multiple_deprecated_definitions)
+
+            actual = self.model.generate_rules(self.sections_info)
+            expected = self.generate_default_rules()
+
+            if perf_level < 4:
+                for append_no in range(1, perf_level + 1):
+                    flash_text_default = self.get_default("flash_text", expected)
+                    flash_rodata_default = self.get_default("flash_rodata", expected)
+
+                    iram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["text"].entries, "iram0_text")
+                    dram_rule = PlacementRule("lib.a", "obj" + str(append_no), None, self.model.sections["rodata"].entries, "dram0_data")
+
+                    flash_text_default.add_exclusion(iram_rule)
+                    flash_rodata_default.add_exclusion(dram_rule)
+
+                    expected["iram0_text"].append(iram_rule)
+                    expected["dram0_data"].append(dram_rule)
+
+            self.compare_rules(expected, actual)
+
 
 if __name__ == "__main__":
     unittest.main()