mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1278 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1278 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
#
 | 
						|
# Copyright 2021 Espressif Systems (Shanghai) CO LTD
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
#     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
#
 | 
						|
 | 
						|
import collections
 | 
						|
import fnmatch
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import tempfile
 | 
						|
import unittest
 | 
						|
 | 
						|
try:
 | 
						|
    from generation import Generation, GenerationException
 | 
						|
except ImportError:
 | 
						|
    sys.path.append('../')
 | 
						|
    from generation import Generation, GenerationException
 | 
						|
 | 
						|
from io import StringIO
 | 
						|
 | 
						|
from entity import Entity, EntityDB
 | 
						|
from fragments import FragmentFile
 | 
						|
from linker_script import LinkerScript
 | 
						|
from output_commands import InputSectionDesc
 | 
						|
from sdkconfig import SDKConfig
 | 
						|
 | 
						|
ROOT = Entity('*')
 | 
						|
 | 
						|
FREERTOS = Entity('libfreertos.a')
 | 
						|
CROUTINE = Entity('libfreertos.a', 'croutine')
 | 
						|
TIMERS = Entity('libfreertos.a', 'timers')
 | 
						|
 | 
						|
FREERTOS2 = Entity('libfreertos2.a')
 | 
						|
 | 
						|
 | 
						|
class GenerationTest(unittest.TestCase):
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        self.generation = Generation()
 | 
						|
        self.entities = None
 | 
						|
        self.linker_script = None
 | 
						|
 | 
						|
        with tempfile.NamedTemporaryFile(delete=False) as f:
 | 
						|
            self.kconfigs_source_file = os.path.join(tempfile.gettempdir(), f.name)
 | 
						|
            self.addCleanup(os.remove, self.kconfigs_source_file)
 | 
						|
        with tempfile.NamedTemporaryFile(delete=False) as f:
 | 
						|
            self.kconfig_projbuilds_source_file = os.path.join(tempfile.gettempdir(), f.name)
 | 
						|
            self.addCleanup(os.remove, self.kconfig_projbuilds_source_file)
 | 
						|
 | 
						|
        os.environ['COMPONENT_KCONFIGS_SOURCE_FILE'] = self.kconfigs_source_file
 | 
						|
        os.environ['COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE'] = self.kconfig_projbuilds_source_file
 | 
						|
        os.environ['COMPONENT_KCONFIGS'] = ''
 | 
						|
        os.environ['COMPONENT_KCONFIGS_PROJBUILD'] = ''
 | 
						|
 | 
						|
        # prepare_kconfig_files.py doesn't have to be called because COMPONENT_KCONFIGS and
 | 
						|
        # COMPONENT_KCONFIGS_PROJBUILD are empty
 | 
						|
 | 
						|
        self.sdkconfig = SDKConfig('data/Kconfig', 'data/sdkconfig')
 | 
						|
 | 
						|
        with open('data/base.lf') as fragment_file_obj:
 | 
						|
            fragment_file = FragmentFile(fragment_file_obj, self.sdkconfig)
 | 
						|
            self.generation.add_fragments_from_file(fragment_file)
 | 
						|
 | 
						|
        self.entities = EntityDB()
 | 
						|
 | 
						|
        with open('data/libfreertos.a.txt') as objdump:
 | 
						|
            self.entities.add_sections_info(objdump)
 | 
						|
 | 
						|
        with open('data/linker_script.ld') as linker_script:
 | 
						|
            self.linker_script = LinkerScript(linker_script)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def create_fragment_file(contents, name='test_fragment.lf'):
 | 
						|
        f = StringIO(contents)
 | 
						|
        f.name = name
 | 
						|
        return f
 | 
						|
 | 
						|
    def add_fragments(self, text):
 | 
						|
        fragment_file = self.create_fragment_file(text)
 | 
						|
        fragment_file = FragmentFile(fragment_file, self.sdkconfig)
 | 
						|
        self.generation.add_fragments_from_file(fragment_file)
 | 
						|
 | 
						|
    def write(self, expected, actual):
 | 
						|
        self.linker_script.fill(expected)
 | 
						|
        self.linker_script.write(open('expected.ld', 'w'))
 | 
						|
 | 
						|
        self.linker_script.fill(actual)
 | 
						|
        self.linker_script.write(open('actual.ld', 'w'))
 | 
						|
 | 
						|
    def generate_default_rules(self):
 | 
						|
        rules = collections.defaultdict(list)
 | 
						|
 | 
						|
        rules['dram0_data'].append(InputSectionDesc(ROOT, ['.data', '.data.*'], []))
 | 
						|
        rules['dram0_data'].append(InputSectionDesc(ROOT, ['.dram', '.dram.*'], []))
 | 
						|
        rules['dram0_bss'].append(InputSectionDesc(ROOT, ['.bss', '.bss.*'], []))
 | 
						|
        rules['dram0_bss'].append(InputSectionDesc(ROOT, ['COMMON'], []))
 | 
						|
        rules['flash_text'].append(InputSectionDesc(ROOT, ['.literal', '.literal.*', '.text', '.text.*'], []))
 | 
						|
        rules['flash_rodata'].append(InputSectionDesc(ROOT, ['.rodata', '.rodata.*'], []))
 | 
						|
        rules['iram0_text'].append(InputSectionDesc(ROOT, ['.iram', '.iram.*'], []))
 | 
						|
        rules['rtc_bss'].append(InputSectionDesc(ROOT, ['.rtc.bss'], []))
 | 
						|
        rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.data'], []))
 | 
						|
        rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.rodata'], []))
 | 
						|
        rules['rtc_text'].append(InputSectionDesc(ROOT, ['.rtc.text', '.rtc.literal'], []))
 | 
						|
 | 
						|
        return rules
 | 
						|
 | 
						|
    def compare_rules(self, expected, actual):
 | 
						|
        self.assertEqual(expected, actual)
 | 
						|
 | 
						|
    def get_default(self, target, rules):
 | 
						|
        return rules[target][0]
 | 
						|
 | 
						|
    def test_rule_generation_default(self):
 | 
						|
        # Checks that default rules are generated from
 | 
						|
        # the default scheme properly and even if no mappings
 | 
						|
        # are defined.
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
 | 
						|
class DefaultMappingTest(GenerationTest):
 | 
						|
 | 
						|
    def test_default_mapping_lib(self):
 | 
						|
        # Mapping a library with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (default)
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
    def test_default_mapping_obj(self):
 | 
						|
        # Mapping an object with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (default)
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
    def test_default_mapping_symbol(self):
 | 
						|
        # Mapping a symbol with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine:prvCheckPendingReadyList (default)                 #1
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
    def test_default_mapping_all(self):
 | 
						|
        # Mapping a library, object, and symbol with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (default)                                     #1
 | 
						|
    croutine (default)                              #2
 | 
						|
    croutine:prvCheckPendingReadyList (default)     #3
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
    def test_default_mapping_lib_symbol(self):
 | 
						|
        # Mapping a library, and symbol with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        #
 | 
						|
        # This is a check needed to make sure generation does not generate
 | 
						|
        # intermediate commands due to presence of symbol mapping.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (default)                                     #1
 | 
						|
    croutine:prvCheckPendingReadyList (default)     #2
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
    def test_default_mapping_obj_symbol(self):
 | 
						|
        # Mapping a library, and symbol with default mapping. This should not emit additional rules,
 | 
						|
        # other than the default ones.
 | 
						|
        #
 | 
						|
        # This is a check needed to make sure generation does not generate
 | 
						|
        # intermediate commands due to presence of symbol mapping.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (default)                              #1
 | 
						|
    croutine:prvCheckPendingReadyList (default)     #2
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        self.test_rule_generation_default()
 | 
						|
 | 
						|
 | 
						|
class BasicTest(GenerationTest):
 | 
						|
    # Test basic and fundamental interactions between typical
 | 
						|
    # entries.
 | 
						|
 | 
						|
    def test_nondefault_mapping_lib(self, alt=None):
 | 
						|
        # Test mapping entry different from default for a library.
 | 
						|
        # There should be exclusions in the default commands for flash_text and flash_rodata:
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *((EXCLUDE_FILE(libfreertos.a)) .literal ...)                                                          A
 | 
						|
        #
 | 
						|
        # Commands placing the entire library in iram, dram should be generated:
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a(.literal  ...)                                                                          B
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (noflash)                     #1
 | 
						|
"""
 | 
						|
        self.add_fragments(alt if alt else mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Generate exclusions in flash_text and flash_rodata                                                 A
 | 
						|
        flash_text[0].exclusions.add(FREERTOS)
 | 
						|
        flash_rodata[0].exclusions.add(FREERTOS)
 | 
						|
 | 
						|
        # Input section commands in iram_text and dram0_data for #1                                          B
 | 
						|
        iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, []))
 | 
						|
        dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_nondefault_mapping_obj(self, alt=None):
 | 
						|
        # Test mapping entry different from default for an object.
 | 
						|
        # There should be exclusions in the default commands for flash_text and flash_rodata:
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...)                                                          A
 | 
						|
        #
 | 
						|
        # Commands placing the entire library in iram, dram should be generated:
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.literal  ...)                                                                          B
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                              #1
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(alt if alt else mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Generate exclusions in flash_text and flash_rodata                                                A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Input section commands in iram_text and dram0_data for #1                                         B
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_nondefault_mapping_symbol(self):
 | 
						|
        # Test mapping entry different from default for symbol.
 | 
						|
        # There should be exclusions in the default commands for flash_text, as well as the implicit intermediate object command
 | 
						|
        # with an exclusion from default:
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...)                                                          A
 | 
						|
        #   *libfreertos.a:croutine(.literal  .literal.prvCheckDelayedList ...)                                             B
 | 
						|
        #
 | 
						|
        # Commands placing the entire library in iram should be generated:
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)                       C
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine:prvCheckPendingReadyList (noflash)         #1
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
 | 
						|
        # Generate exclusion in flash_text                                                A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Generate intermediate command                                                   B
 | 
						|
        # List all relevant sections except the symbol
 | 
						|
        # being mapped
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Input section commands in iram_text for #1                                     C
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_default_symbol_nondefault_lib(self):
 | 
						|
        # Test default symbol mapping with different lib mapping. This should create an implicit intermediate object command.
 | 
						|
        # The significant targets are flash_text, flash_rodata, iram0_text, dram0_data.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a) .text ...)                                                        A
 | 
						|
        #  libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)        B
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a) .rodata ...)                                                      A
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #  * ( .iram ...)
 | 
						|
        #  libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...)                                     C.1
 | 
						|
        #   *libfreertos.a:croutine(.literal  .literal.prvCheckDelayedList ...)                             D
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #  * ( .dram ...)
 | 
						|
        #  libfreertos.a ( .rodata ...)                                                                     C.2
 | 
						|
        #
 | 
						|
        # Only default commands are in the other targets.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (noflash)                                         #1
 | 
						|
    croutine:prvCheckPendingReadyList (default)         #2
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                                 A
 | 
						|
        flash_text[0].exclusions.add(FREERTOS)
 | 
						|
        flash_rodata[0].exclusions.add(FREERTOS)
 | 
						|
 | 
						|
        # Commands for #1                                                                                   C.1 & C.2
 | 
						|
        # C.1 excludes intermediate command for #2
 | 
						|
        iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
 | 
						|
        dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        # Intermediate command for excluding #2                                                             D
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Command for #2                                                                                    B
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_default_symbol_nondefault_obj(self):
 | 
						|
        # Test default symbol mapping with different obj mapping. Since there is an explicit entry for the object,
 | 
						|
        # the sections for that object should just be expanded and the symbol section subtracted, to be placed
 | 
						|
        # using another command.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...)                                                        A
 | 
						|
        #   libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)                B
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...)                                                      A
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *( .iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.literal  .literal.prvCheckDelayedList ...)                                      C.1
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #   *(.data ..)
 | 
						|
        #   *libfreertos.a:croutine(.rodata ....)                                                                    C.2
 | 
						|
        #
 | 
						|
        # Only default commands are in the other targets
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                                  #1
 | 
						|
    croutine:prvCheckPendingReadyList (default)         #2
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Commands for #1                                                                                   C.1 & C.2
 | 
						|
        # C.1 list relevant sections for libfreertos.a:croutine to
 | 
						|
        # exclude symbol to map
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        # Command for #2                                                                                    B
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_default_nondefault_alternating(self):
 | 
						|
        # Here, each of the entries map sections to something different
 | 
						|
        # than its one-level-up entry.
 | 
						|
        #
 | 
						|
        # *                                         text -> flash, rodata -> flash
 | 
						|
        # libfreertos.a                             text -> iram, rodata -> dram
 | 
						|
        # libfreertos.a:croutine                    text -> flash, rodata -> flash
 | 
						|
        # croutine:prvCheckPendingReadyList         text  -> iram
 | 
						|
        #
 | 
						|
        # The significant targets are flash_text, flash_rodata, iram0_text, and dram0_data.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a) .text ...)                                                         A
 | 
						|
        #   *libfreertos.a:croutine(.literal  .literal.prvCheckDelayedList ...)                              B.1
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a) .rodata ...)                                                       A
 | 
						|
        #   *libfreertos.a:croutine(.rodata .rodata.*)                                                       B.2
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #  * ( .iram ...)
 | 
						|
        #  libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...)                                      C
 | 
						|
        #  libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)         D
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #  * ( .dram ...)
 | 
						|
        #  libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .rodata ...)                                    C
 | 
						|
        #
 | 
						|
        # For the other targets only the default commands should be present.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (noflash)                                         #1
 | 
						|
    croutine (default)                                  #2
 | 
						|
    croutine:prvCheckPendingReadyList (noflash)         #3
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                                 A
 | 
						|
        # Only for flash_text and flash_rodata
 | 
						|
        flash_text[0].exclusions.add(FREERTOS)
 | 
						|
        flash_rodata[0].exclusions.add(FREERTOS)
 | 
						|
 | 
						|
        # Commands for #1                                                                                   C
 | 
						|
        # with exclusions for #2
 | 
						|
        iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
 | 
						|
        dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, [CROUTINE]))
 | 
						|
 | 
						|
        # Commands for #2                                                                                   B.1
 | 
						|
        flash_rodata.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        # List all relevant sections in case of flash_text                                                  B.2
 | 
						|
        # as exclusion for #3
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Command for #3                                                                                    D
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_nondefault_but_same_lib_and_obj(self):
 | 
						|
        # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
 | 
						|
        # to #1. Output is similar to test_different_mapping_lib.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (noflash)                                     #1
 | 
						|
    croutine (noflash)                              #2
 | 
						|
"""
 | 
						|
        self.test_nondefault_mapping_lib(mapping)
 | 
						|
 | 
						|
    def test_nondefault_but_same_lib_and_sym(self):
 | 
						|
        # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
 | 
						|
        # to #1. Output is similar to test_different_mapping_lib.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    * (noflash)                                     #1
 | 
						|
    croutine:prvCheckPendingReadyList (noflash)     #2
 | 
						|
"""
 | 
						|
        self.test_nondefault_mapping_lib(mapping)
 | 
						|
 | 
						|
    def test_nondefault_but_same_obj_and_sym(self):
 | 
						|
        # Commands should not be generated for #2, since it does similar mapping
 | 
						|
        # to #1. Output is similar to test_different_mapping_obj.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                                     #1
 | 
						|
    croutine:prvCheckPendingReadyList (noflash)            #2
 | 
						|
"""
 | 
						|
        self.test_nondefault_mapping_obj(mapping)
 | 
						|
 | 
						|
    def test_multiple_symbols_excluded_from_intermediate_command(self):
 | 
						|
        # Test mapping multiple symbols from the same object.
 | 
						|
        # All these symbols must be succesfully excluded from
 | 
						|
        # the intermediate command.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   * (EXCLUDE_FILE(libfreertos.a:croutine) .text ...)                  A
 | 
						|
        #   libfreertos:croutine(.text ...)                                     B
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #
 | 
						|
        #
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine:prvCheckPendingReadyList (noflash)            #1
 | 
						|
    croutine:prvCheckDelayedList (noflash)                 #2
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
 | 
						|
        # Exclusions for #1 & #2 intermediate command                                       A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Intermediate command for #1 & #2 which lists                                      B
 | 
						|
        # all relevant sections in croutine except prvCheckPendingReadyList
 | 
						|
        # and prvCheckDelayedList
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Commands for #1 & 2
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
 | 
						|
class AdvancedTest(GenerationTest):
 | 
						|
 | 
						|
    # Test valid but quirky cases, corner cases, failure cases, and
 | 
						|
    # cases involving interaction between schemes, other mapping
 | 
						|
    # fragments.
 | 
						|
 | 
						|
    def test_same_entity_no_scheme_common(self):
 | 
						|
        # Test same entity being mapped by schemes that have nothing in common.
 | 
						|
        #
 | 
						|
        # noflash_data: rodata -> dram0_data
 | 
						|
        # noflash_text: text -> iram0_text
 | 
						|
        #
 | 
						|
        # This operation should succeed with the following commands:
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...)                                                        A
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...)                                                      B
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.text .text.* ...)                                                               C
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #   *(.data ..)
 | 
						|
        #   *(.dram ...)
 | 
						|
        #   *libfreertos.a:croutine(.rodata .rodata.*)                                                               D
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash_text)                         #1
 | 
						|
    croutine (noflash_data)                         #2
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Exclusions for #2                                                                 B
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Command for #1                                                                    C
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
 | 
						|
 | 
						|
        # Command for #2                                                                    D
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_same_entity_sub_scheme(self):
 | 
						|
        # Test same entity being mapped by scheme that is a subset of the other.
 | 
						|
        #
 | 
						|
        # noflash: text -> iram0_text, rodata -> dram0_data
 | 
						|
        # noflash_text: text -> iram0_text
 | 
						|
        #
 | 
						|
        # `text -> iram0_text` is common between the two schemes.
 | 
						|
        #
 | 
						|
        # This operation should succeed with the following commands:
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...)                                                        A
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...)                                                      B
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.text .text.* ...)                                                               C
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #   *(.data ..)
 | 
						|
        #   *(.dram ...)
 | 
						|
        #   *libfreertos.a:croutine(.rodata .rodata.*)                                                               D
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                              #1
 | 
						|
    croutine (noflash_data)                         #2
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Exclusions for #1 & #2                                                            B
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Command for #1                                                                    C
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
 | 
						|
 | 
						|
        # Command for #1 & #2                                                               D
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_same_entity_conflicting_scheme(self, alt=None):
 | 
						|
        # Test same entity being mapped by scheme conflicting with another.
 | 
						|
        #
 | 
						|
        # rtc = text -> rtc_text, rodata -> rtc_data
 | 
						|
        # noflash = text -> iram0_text, rodata -> dram0_data
 | 
						|
        #
 | 
						|
        # This operation should fail.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                              #1
 | 
						|
    croutine (rtc)                                  #2
 | 
						|
"""
 | 
						|
        self.add_fragments(alt if alt else mapping)
 | 
						|
 | 
						|
        with self.assertRaises(GenerationException):
 | 
						|
            self.generation.generate_rules(self.entities)
 | 
						|
 | 
						|
    def test_complex_mapping_case(self, alt=None):
 | 
						|
        # Test a complex case where an object is mapped using
 | 
						|
        # one scheme, but a specific symbol in that object is mapped
 | 
						|
        # using another. Another object and symbol is mapped the other way around.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .text ...)                                                        A, B
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .rodata ...)                                                      A, B
 | 
						|
        #
 | 
						|
        # dram0_data
 | 
						|
        #   *(EXCLUDE_FILES(libfreertos.a:timers) .data ..)                                                                               B
 | 
						|
        #   *(.dram ...)
 | 
						|
        #   *libfreertos.a:croutine(.rodata .rodata.*)                                                                                    C
 | 
						|
        #   *libfreertos.a:timers(.rodata.prvProcessReceivedCommands ...)                                                                 E
 | 
						|
        #
 | 
						|
        # dram0_bss
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:timers) .bss .bss.* ...)                                                                         B
 | 
						|
        #   *(EXCLUDE_FILE(libfreertos.a:timers) COMMON)                                                                                  B
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #   *(.iram ...)
 | 
						|
        #   *libfreertos.a:croutine(.literal  .literal.prvCheckDelayedList ...)                                                           C
 | 
						|
        #   *libfreertos.a:timers(.literal  .literal.prvProcessReceivedCommands ...)                                                      E
 | 
						|
        #
 | 
						|
        # rtc_text
 | 
						|
        #   *(rtc.text .rtc.literal)
 | 
						|
        #   libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)                                     F
 | 
						|
        #   libfreertos.a:timers (.text .text.prvCheckForValidListAndQueue ...)                                                           D.2
 | 
						|
        #
 | 
						|
        # rtc_data
 | 
						|
        #   *(rtc.data)
 | 
						|
        #   *(rtc.rodata)
 | 
						|
        #   libfreertos.a:timers (.data .data.*)                                                                                          D
 | 
						|
        #   libfreertos.a:timers (.rodata ...)                                                                                            D.2
 | 
						|
        #
 | 
						|
        # rtc_bss
 | 
						|
        #   *(rtc.bss .rtc.bss)
 | 
						|
        #   libfreertos.a:timers (.bss .bss.*)                                                                                            D
 | 
						|
        #   libfreertos.a:timers (COMMON)                                                                                                 D
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                                  #1
 | 
						|
    timers (rtc)                                        #2
 | 
						|
    timers:prvProcessReceivedCommands (noflash)         #3
 | 
						|
    croutine:prvCheckPendingReadyList (rtc)             #4
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(alt if alt else mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_bss = expected['dram0_bss']
 | 
						|
        rtc_text = expected['rtc_text']
 | 
						|
        rtc_data = expected['rtc_data']
 | 
						|
        rtc_bss = expected['rtc_bss']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Exclusions for #2                                                                 B
 | 
						|
        flash_text[0].exclusions.add(TIMERS)
 | 
						|
        flash_rodata[0].exclusions.add(TIMERS)
 | 
						|
        dram0_data[0].exclusions.add(TIMERS)
 | 
						|
        dram0_bss[0].exclusions.add(TIMERS)
 | 
						|
        dram0_bss[1].exclusions.add(TIMERS)
 | 
						|
 | 
						|
        # Commands for #1                                                                   C
 | 
						|
        # List all relevant sections excluding #4 for text -> iram0_text
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        # Commands for #4                                                                   F
 | 
						|
        # Processed first due to alphabetical ordering
 | 
						|
        rtc_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        # Commands for #2                                                                   D
 | 
						|
        # List all relevant sections excluding #3 for text -> rtc_text and                  D.2
 | 
						|
        # rodata -> rtc_data
 | 
						|
        timers_sections = self.entities.get_sections('libfreertos.a', 'timers')
 | 
						|
        filtered_sections = fnmatch.filter(timers_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(timers_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
        rtc_text.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
 | 
						|
 | 
						|
        rtc_data.append(InputSectionDesc(TIMERS, dram0_data[0].sections, []))
 | 
						|
        filtered_sections = fnmatch.filter(timers_sections, '.rodata.*')
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
 | 
						|
        rtc_data.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
 | 
						|
 | 
						|
        rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[0].sections, []))
 | 
						|
        rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[1].sections, []))
 | 
						|
 | 
						|
        # Commands for #3                                                                  E
 | 
						|
        iram0_text.append(InputSectionDesc(TIMERS, set(['.text.prvProcessReceivedCommands', '.literal.prvProcessReceivedCommands']), []))
 | 
						|
        dram0_data.append(InputSectionDesc(TIMERS, set(['.rodata.prvProcessReceivedCommands']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_multiple_mapping_fragments(self):
 | 
						|
        # Test mapping multiple fragments succeeds, particularly
 | 
						|
        # generating exclusions from the default command of archive
 | 
						|
        # and object specificity.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
 | 
						|
        #
 | 
						|
        # flash_rodata
 | 
						|
        #   * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test_1]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                              #1
 | 
						|
 | 
						|
[mapping:test_2]
 | 
						|
archive: libfreertos2.a
 | 
						|
entries:
 | 
						|
    * (noflash)                                     #2
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        flash_rodata = expected['flash_rodata']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
        dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
        flash_rodata[0].exclusions.add(CROUTINE)
 | 
						|
 | 
						|
        # Exclusions for #1 & #2                                                            B
 | 
						|
        flash_text[0].exclusions.add(FREERTOS2)
 | 
						|
        flash_rodata[0].exclusions.add(FREERTOS2)
 | 
						|
 | 
						|
        # Command for #1                                                                    C
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
 | 
						|
        dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        # Command for #1 & #2                                                               D
 | 
						|
        iram0_text.append(InputSectionDesc(FREERTOS2, flash_text[0].sections, []))
 | 
						|
        dram0_data.append(InputSectionDesc(FREERTOS2, flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_mapping_same_lib_in_multiple_fragments_no_conflict(self):
 | 
						|
        # Test mapping fragments operating on the same archive.
 | 
						|
        # In these cases, the entries are taken together.
 | 
						|
        #
 | 
						|
        # Uses the same entries as C_05 but spreads them across
 | 
						|
        # two fragments. The output should still be the same.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test_1]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                                  #1
 | 
						|
    timers:prvProcessReceivedCommands (noflash)         #3
 | 
						|
 | 
						|
[mapping:test_2]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    timers (rtc)                                        #2
 | 
						|
    croutine:prvCheckPendingReadyList (rtc)             #4
 | 
						|
"""
 | 
						|
        self.test_complex_mapping_case(mapping)
 | 
						|
 | 
						|
    def test_mapping_same_lib_in_multiple_fragments_conflict(self):
 | 
						|
        # Test mapping fragments operating on the same archive
 | 
						|
        # with conflicting mappings.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test_1]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (noflash)                              #1
 | 
						|
 | 
						|
[mapping:test_2]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine (rtc)                                  #2
 | 
						|
"""
 | 
						|
        self.test_same_entity_conflicting_scheme(mapping)
 | 
						|
 | 
						|
    def test_command_order(self):
 | 
						|
        # Test command order sorting: the commands should be sorted by specificity, then
 | 
						|
        # alphabetically. This contributes to deterministic output given
 | 
						|
        # the same input mapping entries.
 | 
						|
        #
 | 
						|
        # This ordering is also tested in other tests as a side-effect.
 | 
						|
        #
 | 
						|
        # flash_text
 | 
						|
        #   * (EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:croutine2))                                    A
 | 
						|
        #   libfreertos.a:croutine(.text ....)                                                                  B
 | 
						|
        #
 | 
						|
        # iram0_text
 | 
						|
        #
 | 
						|
        #   * (.iram .iram.*)
 | 
						|
        #   libfreertos:croutine(.text .literal ...)                                                            C
 | 
						|
        #   libfreertos:croutine(.text.prvCheckDelayedList .literal.prvCheckDelayedList)                        F
 | 
						|
        #   libfreertos:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList)              G
 | 
						|
        #   libfreertos2:croutine(.text .literal ...)                                                           D
 | 
						|
        #   libfreertos2:croutine2(.text .literal ...)                                                          E
 | 
						|
        mapping = u"""
 | 
						|
[mapping:freertos2]
 | 
						|
archive: libfreertos2.a
 | 
						|
entries:
 | 
						|
    croutine2 (noflash_text)                                    #1
 | 
						|
    croutine (noflash_text)                                     #2
 | 
						|
 | 
						|
[mapping:freertos]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    croutine:prvCheckPendingReadyList (noflash_text)            #3
 | 
						|
    croutine:prvCheckDelayedList (noflash_text)                 #4
 | 
						|
"""
 | 
						|
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
 | 
						|
        # Exclusions for #1                                                                 A
 | 
						|
        flash_text[0].exclusions.add(CROUTINE)
 | 
						|
        flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine2'))
 | 
						|
        flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine'))
 | 
						|
 | 
						|
        # Intermediate command for #3 and #4                                                B
 | 
						|
        croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
 | 
						|
 | 
						|
        filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
        flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Command for
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
 | 
						|
        iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
 | 
						|
 | 
						|
        iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine'), flash_text[0].sections, []))
 | 
						|
        iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine2'), flash_text[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_ambigious_obj(self):
 | 
						|
        # Command generation for ambiguous entry should fail.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    port:xPortGetTickRateHz (noflash)                 #1
 | 
						|
"""
 | 
						|
        self.add_fragments(mapping)
 | 
						|
 | 
						|
        with self.assertRaises(GenerationException):
 | 
						|
            self.generation.generate_rules(self.entities)
 | 
						|
 | 
						|
    def test_disambiguated_obj(self):
 | 
						|
        # Test command generation for disambiguated entry. Should produce similar
 | 
						|
        # results to test_nondefault_mapping_symbol.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: libfreertos.a
 | 
						|
entries:
 | 
						|
    port.c:xPortGetTickRateHz (noflash)                 #1
 | 
						|
"""
 | 
						|
        port = Entity('libfreertos.a', 'port.c')
 | 
						|
        self.add_fragments(mapping)
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        flash_text = expected['flash_text']
 | 
						|
        iram0_text = expected['iram0_text']
 | 
						|
 | 
						|
        # Generate exclusion in flash_text                                                A
 | 
						|
        flash_text[0].exclusions.add(port)
 | 
						|
 | 
						|
        # Generate intermediate command                                                   B
 | 
						|
        # List all relevant sections except the symbol
 | 
						|
        # being mapped
 | 
						|
        port_sections = self.entities.get_sections('libfreertos.a', 'port.c')
 | 
						|
        filtered_sections = fnmatch.filter(port_sections, '.literal.*')
 | 
						|
        filtered_sections.extend(fnmatch.filter(port_sections, '.text.*'))
 | 
						|
 | 
						|
        filtered_sections = [s for s in filtered_sections if not s.endswith('xPortGetTickRateHz')]
 | 
						|
        filtered_sections.append('.text')
 | 
						|
 | 
						|
        flash_text.append(InputSectionDesc(port, set(filtered_sections), []))
 | 
						|
 | 
						|
        # Input section commands in iram_text for #1                                     C
 | 
						|
        iram0_text.append(InputSectionDesc(port, set(['.text.xPortGetTickRateHz', '.literal.xPortGetTickRateHz']), []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
 | 
						|
class ConfigTest(GenerationTest):
 | 
						|
    # Test command generation with conditions
 | 
						|
 | 
						|
    def _test_conditional_on_scheme(self, perf, alt=None):
 | 
						|
        # Test that proper commands are generated if using
 | 
						|
        # schemes with conditional entries.
 | 
						|
        scheme = u"""
 | 
						|
[sections:cond_text_data]
 | 
						|
entries:
 | 
						|
    if PERFORMANCE_LEVEL >= 1:
 | 
						|
        .text+
 | 
						|
        .literal+
 | 
						|
    else:
 | 
						|
        .rodata+
 | 
						|
 | 
						|
[scheme:cond_noflash]
 | 
						|
entries:
 | 
						|
    if PERFORMANCE_LEVEL >= 1:
 | 
						|
        cond_text_data -> iram0_text
 | 
						|
    else:
 | 
						|
        cond_text_data -> dram0_data
 | 
						|
"""
 | 
						|
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: lib.a
 | 
						|
entries:
 | 
						|
    * (cond_noflash)
 | 
						|
"""
 | 
						|
        self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf))
 | 
						|
        self.add_fragments(scheme)
 | 
						|
        self.add_fragments(alt if alt else mapping)
 | 
						|
 | 
						|
        actual = self.generation.generate_rules(self.entities)
 | 
						|
        expected = self.generate_default_rules()
 | 
						|
 | 
						|
        if perf >= 1:
 | 
						|
            flash_text = expected['flash_text']
 | 
						|
            iram0_text = expected['iram0_text']
 | 
						|
            flash_text[0].exclusions.add(Entity('lib.a'))
 | 
						|
            iram0_text.append(InputSectionDesc(Entity('lib.a'), flash_text[0].sections, []))
 | 
						|
        else:
 | 
						|
            flash_rodata = expected['flash_rodata']
 | 
						|
            dram0_data = expected['dram0_data']
 | 
						|
            flash_rodata[0].exclusions.add(Entity('lib.a'))
 | 
						|
            dram0_data.append(InputSectionDesc(Entity('lib.a'), flash_rodata[0].sections, []))
 | 
						|
 | 
						|
        self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_conditional_on_scheme_00(self):
 | 
						|
        self._test_conditional_on_scheme(0)
 | 
						|
 | 
						|
    def test_conditional_on_scheme_01(self):
 | 
						|
        self._test_conditional_on_scheme(1)
 | 
						|
 | 
						|
    def test_conditional_mapping(self, alt=None):
 | 
						|
        # Test that proper commands are generated
 | 
						|
        # in conditional mapping entries.
 | 
						|
        mapping = u"""
 | 
						|
[mapping:test]
 | 
						|
archive: lib.a
 | 
						|
entries:
 | 
						|
    if PERFORMANCE_LEVEL = 1:
 | 
						|
        obj1 (noflash)
 | 
						|
    elif PERFORMANCE_LEVEL = 2:
 | 
						|
        obj1 (noflash)
 | 
						|
        obj2 (noflash)
 | 
						|
    elif PERFORMANCE_LEVEL = 3:
 | 
						|
        obj1 (noflash)
 | 
						|
        obj2 (noflash)
 | 
						|
        obj3 (noflash)
 | 
						|
"""
 | 
						|
 | 
						|
        for perf_level in range(0, 4):
 | 
						|
            self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf_level))
 | 
						|
 | 
						|
            self.generation.mappings = {}
 | 
						|
            self.add_fragments(alt if alt else mapping)
 | 
						|
 | 
						|
            actual = self.generation.generate_rules(self.entities)
 | 
						|
            expected = self.generate_default_rules()
 | 
						|
 | 
						|
            if perf_level < 4 and perf_level > 0:
 | 
						|
                for append_no in range(1, perf_level + 1):
 | 
						|
                    flash_text = expected['flash_text']
 | 
						|
                    flash_rodata = expected['flash_rodata']
 | 
						|
                    iram0_text = expected['iram0_text']
 | 
						|
                    dram0_data = expected['dram0_data']
 | 
						|
 | 
						|
                    obj_str = 'obj' + str(append_no)
 | 
						|
 | 
						|
                    flash_text[0].exclusions.add(Entity('lib.a', obj_str))
 | 
						|
                    flash_rodata[0].exclusions.add(Entity('lib.a', obj_str))
 | 
						|
 | 
						|
                    iram0_text.append(InputSectionDesc(Entity('lib.a', obj_str), flash_text[0].sections, []))
 | 
						|
                    dram0_data.append(InputSectionDesc(Entity('lib.a', obj_str), flash_rodata[0].sections, []))
 | 
						|
 | 
						|
            self.compare_rules(expected, actual)
 | 
						|
 | 
						|
    def test_conditional_on_scheme_legacy_mapping_00(self):
 | 
						|
        # Test use of conditional scheme on legacy mapping fragment grammar.
 | 
						|
        mapping = u"""
 | 
						|
[mapping]
 | 
						|
archive: lib.a
 | 
						|
entries:
 | 
						|
    * (cond_noflash)
 | 
						|
"""
 | 
						|
        self._test_conditional_on_scheme(0, mapping)
 | 
						|
 | 
						|
    def test_conditional_on_scheme_legacy_mapping_01(self):
 | 
						|
        # Test use of conditional scheme on legacy mapping fragment grammar.
 | 
						|
        mapping = u"""
 | 
						|
[mapping]
 | 
						|
archive: lib.a
 | 
						|
entries:
 | 
						|
    * (cond_noflash)
 | 
						|
"""
 | 
						|
        self._test_conditional_on_scheme(0, mapping)
 | 
						|
 | 
						|
    def test_conditional_entries_legacy_mapping_fragment(self):
 | 
						|
        # Test conditional entries on legacy mapping fragment grammar.
 | 
						|
        mapping = u"""
 | 
						|
[mapping]
 | 
						|
archive: lib.a
 | 
						|
entries:
 | 
						|
    : PERFORMANCE_LEVEL = 0
 | 
						|
    : PERFORMANCE_LEVEL = 1
 | 
						|
    obj1 (noflash)
 | 
						|
    : PERFORMANCE_LEVEL = 2
 | 
						|
    obj1 (noflash)
 | 
						|
    obj2 (noflash)
 | 
						|
    : PERFORMANCE_LEVEL = 3
 | 
						|
    obj1 (noflash)
 | 
						|
    obj2 (noflash)
 | 
						|
    obj3 (noflash)
 | 
						|
"""
 | 
						|
        self.test_conditional_mapping(mapping)
 | 
						|
 | 
						|
    def test_multiple_fragment_same_lib_conditional_legacy(self):
 | 
						|
        # Test conditional entries on legacy mapping fragment grammar
 | 
						|
        # across multiple fragments.
 | 
						|
        mapping = 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)
 | 
						|
"""
 | 
						|
 | 
						|
        self.test_conditional_mapping(mapping)
 | 
						|
 | 
						|
    def test_multiple_fragment_same_lib_conditional(self):
 | 
						|
        # Test conditional entries on new mapping fragment grammar.
 | 
						|
        # across multiple fragments.
 | 
						|
        mapping = 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)
 | 
						|
 | 
						|
[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)
 | 
						|
"""
 | 
						|
 | 
						|
        self.test_conditional_mapping(mapping)
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    unittest.main()
 |