source: rtems/rtems-bsps

Last change on this file was d64e10e, checked in by Chris Johns <chrisj@…>, on 10/27/22 at 21:40:53

rtems-bsps: Generate empty config.ini for arc/bsp combinations

  • Generate a config for all BSPs in an arch
  • Property mode set to 100755
File size: 17.3 KB
Line 
1#! /usr/bin/env python
2#
3# RTEMS (http://www.rtems.org/)
4# Copyright 2020, 2022 Chris Johns (chrisj@rtems.org)
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9#
10# 1. Redistributions of source code must retain the above copyright notice,
11# this list of conditions and the following disclaimer.
12#
13# 2. Redistributions in binary form must reproduce the above copyright notice,
14# this list of conditions and the following disclaimer in the documentation
15# and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29
30from __future__ import print_function
31
32import argparse
33import os
34import os.path
35import re
36import sys
37
38rtems_version = 6
39
40
41_BUILD_TYPE_BSP = re.compile(r"build-type:\s*bsp\n")
42_ARCH = re.compile(r"arch:\s*(\S+)\n")
43_FAMILY = re.compile(r"family:\s*(\S+)\n")
44_BSP = re.compile(r"bsp:\s*(\S+)\n")
45
46
47class ArchBsps:
48    """Collects and processes the BSPs for a range of architectures
49    creating output in text, markdown and HTML ir pandoc is installed"""
50    def __init__(self, path='.', trace=False):
51        self.trace = trace
52        self._output = []
53        self.top = os.path.realpath(path)
54        self.base = os.path.join(self.top, 'spec', 'build', 'bsps')
55        self.configs = []
56        self.archs = {}
57        self._collect('.yml')
58        self._process()
59
60    def _clear(self):
61        """Clears the output."""
62        self._output = []
63
64    def _out(self, line=''):
65        """Output a line to the output buffer."""
66        if isinstance(line, list):
67            self._output += line
68        else:
69            self._output += [line]
70
71    def _collect(self, ext):
72        """Collect the config files from the source tree."""
73        self.configs = []
74        for root, dirs, files in os.walk(self.base, topdown=True):
75            for f in files:
76                if os.path.splitext(f)[1] == ext:
77                    self.configs += [os.path.join(root, f)]
78
79    def _process(self):
80        """Process the collected list of config files."""
81        self.archs = {}
82        for cfg in self.configs:
83            with open(cfg, 'r') as cfg_file:
84                content = cfg_file.read()
85                if _BUILD_TYPE_BSP.search(content):
86                    arch = _ARCH.search(content).group(1)
87                    family = _FAMILY.search(content).group(1)
88                    bsp = _BSP.search(content).group(1)
89                    self.archs.setdefault(arch, {})
90                    self.archs[arch].setdefault(family, {})
91                    self.archs[arch][family][bsp] = cfg[len(self.base) + 1:]
92
93    def _max_arch_len(self):
94        """Finds the longest arch label"""
95        maxlen = 0
96        for arch in self.archs:
97            if len(arch) > maxlen:
98                maxlen = len(arch)
99        return maxlen
100
101    def _max_family_len(self):
102        """Finds the longest family label"""
103        maxlen = 0
104        for arch in self.archs:
105            for family in self.archs[arch]:
106                if len(family) > maxlen:
107                    maxlen = len(family)
108        return maxlen
109
110    def _max_bsp_len(self):
111        """Finds the longest BSP label"""
112        maxlen = 0
113        for arch in self.archs:
114            for family in self.archs[arch]:
115                for bsp in self.archs[arch][family]:
116                    if len(bsp) > maxlen:
117                        maxlen = len(bsp)
118        return maxlen
119
120    def _max_bsp_path_len(self):
121        """Finds the longest BSP path"""
122        maxlen = 0
123        for arch in self.archs:
124            for family in self.archs[arch]:
125                for bsp in self.archs[arch][family]:
126                    if len(self.archs[arch][family][bsp]) > maxlen:
127                        maxlen = len(self.archs[arch][family][bsp])
128        return maxlen
129
130    def title(self):
131        """Returns the output's title"""
132        return 'RTEMS %d Board Support Packages' % (rtems_version)
133
134    def output(self):
135        """Return the output"""
136        return self._output
137
138    def architectures(self):
139        """Returns the number of architectures we have"""
140        return len(self.archs)
141
142    def families(self, arch=None):
143        """Returns the number of BSP families we have for an architecture. If
144        you supply an architecture the count is the families in the
145        architure.
146
147        """
148        if arch is not None:
149            return len(self.archs[arch])
150        count = 0
151        for arch in self.archs:
152            count += len(self.archs[arch])
153        return count
154
155    def bsps(self, arch=None, family=None):
156        """Returns the number of BSPs we have for an architecture or a family"""
157        count = 0
158        if arch is not None and family is not None:
159            count = len(self.archs[arch][family])
160        elif arch is None and family is not None:
161            for arch in self.archs:
162                if family in self.archs[arch]:
163                    count = len(self.archs[arch][family])
164                    break
165        elif arch is not None and family is None:
166            count = 0
167            for family in self.archs[arch]:
168                count += len(self.archs[arch][family])
169        else:
170            for arch in self.archs:
171                for family in self.archs[arch]:
172                    count += len(self.archs[arch][family])
173        return count
174
175    def text(self, arch_selector=None, family_selector=None, show_path=False):
176        """Generate plain text output"""
177        self._clear()
178        self._out(self.title())
179        self._out()
180        self._out('Architectures: %d' % (self.architectures()))
181        self._out('BSP Families: %d' % (self.families()))
182        self._out('BSPs: %d' % (self.bsps()))
183        max_family = self._max_family_len()
184        max_bsp = self._max_bsp_len()
185        if arch_selector is None:
186            archs_matcher = []
187        else:
188            archs_matcher = [a.strip() for a in arch_selector.split(',')]
189        if family_selector is None:
190            family_matcher = []
191        else:
192            family_matcher = [f.strip() for f in family_selector.split(',')]
193        for arch in sorted(self.archs.keys()):
194            if arch_selector is None or arch in archs_matcher:
195                first = True
196                for family in sorted(self.archs[arch].keys()):
197                    if family_selector is None or family in family_matcher:
198                        if first:
199                            self._out()
200                            self._out('%s: (families:%d bsps:%d)' % \
201                                      (arch,
202                                       self.families(arch=arch),
203                                       self.bsps(arch=arch)))
204                            first = False
205                        for bsp in sorted(self.archs[arch][family].keys()):
206                            if show_path:
207                                p = os.path.join('bsps',
208                                                 self.archs[arch][family][bsp])
209                                self._out(' %-*s %-*s %s' % \
210                                          (max_bsp, bsp, max_family, family, p))
211                            else:
212                                self._out(' %-*s %s' % (max_bsp, bsp, family))
213
214    def markdown(self,
215                 arch_selector=None,
216                 family_selector=None,
217                 show_path=False,
218                 show_title=False):
219        """Generates markdown output"""
220        self._clear()
221        if show_title:
222            self._out('# ' + self.title())
223            self._out()
224        self._out('**Architectures:** %d  ' % (self.architectures()))
225        self._out('**BSP Families:** %d  ' % (self.families()))
226        self._out('**BSPs:** %d  ' % (self.bsps()))
227        max_arch = self._max_arch_len()
228        max_family = self._max_family_len()
229        max_bsp = self._max_bsp_len()
230        max_bsp_path = self._max_bsp_path_len() + 4
231        if arch_selector is None:
232            archs_matcher = []
233        else:
234            archs_matcher = [a.strip() for a in arch_selector.split(',')]
235        if family_selector is None:
236            family_matcher = []
237        else:
238            family_matcher = [f.strip() for f in family_selector.split(',')]
239        for arch in sorted(self.archs.keys()):
240            if arch_selector is None or arch in archs_matcher:
241                first = True
242                for family in sorted(self.archs[arch].keys()):
243                    if family_selector is None or family in family_matcher:
244                        if first:
245                            fbs = 'families:%-2d bsps:%-3d' % \
246                                (self.families(arch=arch),
247                                 self.bsps(arch=arch))
248                            if max_family < len(fbs):
249                                max_fb = len(fbs)
250                            else:
251                                max_fb = max_family
252                            self._out()
253                            if show_path:
254                                self._out('%-*s |%-*s |' %
255                                          (max_bsp, arch, max_fb, fbs))
256                                self._out('%s-|%s-|-%s' %
257                                          ('-' * max_bsp, '-' * max_fb,
258                                           '-' * max_bsp_path))
259                            else:
260                                self._out('%-*s |%s' % (max_bsp, arch, fbs))
261                                self._out('%s-|-%s' %
262                                          ('-' * max_bsp, '-' * max_fb))
263                            first = False
264                        for bsp in sorted(self.archs[arch][family].keys()):
265                            if show_path:
266                                p = os.path.join('bsps',
267                                                 self.archs[arch][family][bsp])
268                                self._out('%-*s |%-*s |%s' % \
269                                          (max_bsp, bsp, max_fb, family, p))
270                            else:
271                                self._out('%-*s |%s' % (max_bsp, bsp, family))
272
273    def pairs(self, arch_selector=None, family_selector=None, show_path=False):
274        """Generate output as pairs"""
275        self._clear()
276        max_arch = self._max_arch_len()
277        max_bsp = self._max_bsp_len()
278        if arch_selector is None:
279            arch_matcher = []
280        else:
281            arch_matcher = [a.strip() for a in arch_selector.split(',')]
282        if family_selector is None:
283            family_matcher = []
284        else:
285            family_matcher = [f.strip() for f in family_selector.split(',')]
286        for arch in sorted(self.archs.keys()):
287            if arch_selector is None or arch in arch_matcher:
288                for family in sorted(self.archs[arch].keys()):
289                    if family_selector is None or family in family_matcher:
290                        for bsp in sorted(self.archs[arch][family].keys()):
291                            if show_path:
292                                p = os.path.join('bsps',
293                                                 self.archs[arch][family][bsp])
294                                pair = arch + '/' + bsp
295                                pair = '%-*s %s' % (max_arch + max_bsp + 1, pair, p)
296
297                                self._out(pair)
298                            else:
299                                self._out('%s/%s' % (arch, bsp))
300
301    def config(self, arch_selector=None, family_selector=None):
302        """Generate output as pairs"""
303        self._clear()
304        self._out(['# Generated by rtems-bsp',
305                   '[DEFAULT]',
306                   '# Build',
307                   'RTEMS_BUILD_LABEL = DEFAULT',
308                   'RTEMS_DEBUG = False',
309                   'RTEMS_PROFILING = False',
310                   'RTEMS_POSIX_API = True',
311                   '# Tests',
312                   'BUILD_TESTS = False',
313                   'BUILD_BENCHMARKS = False',
314                   'BUILD_FSTESTS = False',
315                   'BUILD_LIBTESTS = False',
316                   'BUILD_MPTESTS = False',
317                   'BUILD_PSXTESTS = False',
318                   'BUILD_PSXTMTESTS = False',
319                   'BUILD_RHEALSTONE = False',
320                   'BUILD_SAMPLES = True',
321                   'BUILD_SMPTESTS = False',
322                   'BUILD_SPTESTS = False',
323                   'BUILD_TMTESTS = False',
324                   'BUILD_UNITTESTS = False',
325                   'BUILD_VALIDATIONTESTS = False',
326                   'RTEMS_TEST_VERBOSITY = Normal',
327                   '# Compliler',
328                   '; WARNING_FLAGS = -Wall',
329                   '; CC_WARNING_FLAGS = -Wmissing-prototypes -Wimplicit-function-declaration -Wstrict-prototypes -Wnested-externs',
330                   '; CXX_WARNING_FLAGS = ',
331                   '; OPTIMIZATION_FLAGS = -O2 -g -fdata-sections -ffunction-sections',
332                   '; BSP_OPTIMIZATION_FLAGS = ${OPTIMIZATION_FLAGS}',
333                   '; CPUKIT_OPTIMIZATION_FLAGS = ${OPTIMIZATION_FLAGS}',
334                   '; TEST_OPTIMIZATION_FLAGS = ${OPTIMIZATION_FLAGS}',
335                   '; LINKFLAGS = ',
336                   '; LDFLAGS = -Wl,--gc-sections',
337                   '# BSP',
338                   'BSP_VERBOSE_FATAL_EXTENSION = 1',
339                   'BSP_PRINT_EXCEPTION_CONTEXT = 1',
340                   'BSP_RESET_BOARD_AT_EXIT = 1'])
341        self._out()
342        max_arch = self._max_arch_len()
343        max_bsp = self._max_bsp_len()
344        if arch_selector is None:
345            arch_matcher = []
346        else:
347            arch_matcher = [a.strip() for a in arch_selector.split(',')]
348        if family_selector is None:
349            family_matcher = []
350        else:
351            family_matcher = [f.strip() for f in family_selector.split(',')]
352        for arch in sorted(self.archs.keys()):
353            if arch_selector is None or arch in arch_matcher:
354                for family in sorted(self.archs[arch].keys()):
355                    if family_selector is None or family in family_matcher:
356                        for bsp in sorted(self.archs[arch][family].keys()):
357                            self._out('[%s/%s]' % (arch, bsp))
358                            self._out()
359
360
361def run(args):
362    """Runs the command"""
363    argsp = argparse.ArgumentParser(
364        prog='rtems-bsps',
365        description='List the BSP and architectures in RTEMS')
366    argsp.add_argument('-a',
367                       '--arch',
368                       help='Output the BSPs in an architecture',
369                       type=str,
370                       default=None)
371    argsp.add_argument('-f',
372                       '--family',
373                       help='Output the BSPs in an architecture family',
374                       type=str,
375                       default=None)
376    argsp.add_argument('-p',
377                       '--paths',
378                       help='Show the BSP paths in the output',
379                       action='store_true')
380    argsp.add_argument('-m',
381                       '--markdown',
382                       help='Output list in markdown format',
383                       action='store_true')
384    argsp.add_argument('-T',
385                       '--title',
386                       help='Output a title in the markdown format',
387                       action='store_true')
388    argsp.add_argument('-v',
389                       '--trace',
390                       help='Verbose or trace for debugging',
391                       action='store_true')
392    argsp.add_argument('-P',
393                       '--pairs',
394                       help='Output architectures and BSPs in CPU/BSP format',
395                       action='store_true')
396    argsp.add_argument('-C',
397                       '--config',
398                       help='Output architectures and BSPs in `config.ini` format',
399                       action='store_true')
400
401    argopts = argsp.parse_args(args[1:])
402
403    if argopts.arch is not None and argopts.family is not None:
404        print('error: arch or family, not both at once', file=sys.stderr)
405        sys.exit(1)
406
407    ab = ArchBsps(trace=argopts.trace)
408
409    if argopts.markdown:
410        ab.markdown(arch_selector=argopts.arch,
411                    family_selector=argopts.family,
412                    show_path=argopts.paths,
413                    show_title=argopts.title)
414    elif argopts.pairs:
415        ab.pairs(arch_selector=argopts.arch,
416                 family_selector=argopts.family,
417                 show_path=argopts.paths)
418    elif argopts.config:
419        ab.config(arch_selector=argopts.arch,
420                 family_selector=argopts.family)
421    else:
422        ab.text(arch_selector=argopts.arch,
423                family_selector=argopts.family,
424                show_path=argopts.paths)
425
426    print(os.linesep.join(ab.output()))
427
428
429if __name__ == "__main__":
430    run(sys.argv)
Note: See TracBrowser for help on using the repository browser.