source: rtems/wscript @ 641b31a4

Last change on this file since 641b31a4 was 11c1b862, checked in by Sebastian Huber <sebastian.huber@…>, on 09/17/20 at 10:55:25

build: Allow test program item UIDs with a "-"

Update #3818.

  • Property mode set to 100755
File size: 49.5 KB
Line 
1#!/usr/bin/env python
2
3# SPDX-License-Identifier: BSD-2-Clause
4#
5# Copyright (C) 2020 Hesham Almatary <Hesham.Almatary@cl.cam.ac.uk>
6# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de)
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation 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 OWNER 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
29from __future__ import print_function
30
31import pickle
32import os
33import re
34import stat
35import string
36import sys
37
38try:
39    import configparser
40except:
41    import ConfigParser as configparser
42
43from waflib.TaskGen import after, before_method, feature
44
45is_windows_host = os.name == "nt" or sys.platform in ["msys", "cygwin"]
46default_prefix = "/opt/rtems/6"
47compilers = ["gcc", "clang"]
48items = {}
49bsps = {}
50
51
52def no_unicode(value):
53    if sys.version_info[0] > 2:
54        return value
55    if isinstance(value, unicode):
56        return str(value)
57    return value
58
59
60class VersionControlKeyHeader:
61    _content = None
62
63    @staticmethod
64    def write(bld, filename):
65        if VersionControlKeyHeader._content is None:
66            from waflib.Build import Context
67            from waflib.Errors import WafError
68
69            content = """/*
70 * Automatically generated. Do not edit.
71 */
72#if !defined(_RTEMS_VERSION_VC_KEY_H_)
73#define _RTEMS_VERSION_VC_KEY_H_
74"""
75            try:
76                rev = bld.cmd_and_log(
77                    "git rev-parse HEAD", quiet=Context.STDOUT
78                ).strip()
79                content += """#define RTEMS_VERSION_VC_KEY "{}"
80""".format(
81                    rev
82                )
83            except WafError:
84                content += """/* No version control key found; release? */
85"""
86            content += """#endif
87"""
88            VersionControlKeyHeader._content = content
89        f = bld.bldnode.make_node(filename)
90        f.parent.mkdir()
91        try:
92            if content != f.read():
93                f.write(VersionControlKeyHeader._content)
94        except:
95            f.write(VersionControlKeyHeader._content)
96
97
98class EnvWrapper(object):
99    def __init__(self, env):
100        self._env = env
101
102    def __getitem__(self, name):
103        fields = name.split(":")
104        v = self._env[fields[0]]
105        try:
106            fmt = "{:" + fields[1] + "}"
107        except IndexError:
108            fmt = "{}"
109        if isinstance(v, list):
110            return " ".join([fmt.format(w) for w in v])
111        return fmt.format(v)
112
113
114class Template(string.Template):
115    idpattern = "[_a-z][_a-z0-9:#]*"
116
117
118def _is_enabled_op_and(enabled, enabled_by):
119    for next_enabled_by in enabled_by:
120        if not _is_enabled(enabled, next_enabled_by):
121            return False
122    return True
123
124
125def _is_enabled_op_not(enabled, enabled_by):
126    return not _is_enabled(enabled, enabled_by)
127
128
129def _is_enabled_op_or(enabled, enabled_by):
130    for next_enabled_by in enabled_by:
131        if _is_enabled(enabled, next_enabled_by):
132            return True
133    return False
134
135
136_IS_ENABLED_OP = {
137    "and": _is_enabled_op_and,
138    "not": _is_enabled_op_not,
139    "or": _is_enabled_op_or,
140}
141
142
143def _is_enabled(enabled, enabled_by):
144    if isinstance(enabled_by, bool):
145        return enabled_by
146    if isinstance(enabled_by, list):
147        return _is_enabled_op_or(enabled, enabled_by)
148    if isinstance(enabled_by, dict):
149        key, value = next(iter(enabled_by.items()))
150        return _IS_ENABLED_OP[key](enabled, value)
151    return enabled_by in enabled
152
153
154def _asm_explicit_target(self, node):
155    task = self.create_task(
156        "asm", node, self.bld.bldnode.make_node(self.target)
157    )
158    try:
159        self.compiled_tasks.append(task)
160    except AttributeError:
161        self.compiled_tasks = [task]
162    return task
163
164
165@feature("asm_explicit_target")
166@before_method("process_source")
167def _enable_asm_explicit_target(self):
168    self.mappings = dict(self.mappings)  # Copy
169    self.mappings[".S"] = _asm_explicit_target
170
171
172@after("apply_link")
173@feature("cprogram", "cxxprogram")
174def process_start_files(self):
175    if getattr(self, "start_files", False):
176        self.link_task.dep_nodes.extend(self.bld.start_files)
177
178
179class Item(object):
180    def __init__(self, uid, data):
181        self.uid = uid
182        self.data = data
183        self.links = self._init_links
184
185    def _init_links(self):
186        self._links = []
187        for link in self.data["links"]:
188            if link["role"] == "build-dependency":
189                uid = link["uid"]
190                if not os.path.isabs(uid):
191                    uid = os.path.normpath(
192                        os.path.join(os.path.dirname(self.uid), uid)
193                    )
194                self._links.append(items[uid])
195        self.links = self._yield_links
196        for link in self._links:
197            yield link
198
199    def _yield_links(self):
200        for link in self._links:
201            yield link
202
203    def get_enabled_by(self):
204        return self.data["enabled-by"]
205
206    def defaults(self, enable, variant):
207        if _is_enabled(enable, self.get_enabled_by()):
208            for p in self.links():
209                p.defaults(enable, variant)
210            self.do_defaults(variant)
211
212    def configure(self, conf, cic):
213        if _is_enabled(conf.env.ENABLE, self.get_enabled_by()):
214            self.prepare_configure(conf, cic)
215            for p in self.links():
216                p.configure(conf, cic)
217            self.do_configure(conf, cic)
218
219    def build(self, bld, bic):
220        if _is_enabled(bld.env.ENABLE, self.get_enabled_by()):
221            bic = self.prepare_build(bld, bic)
222            for p in self.links():
223                p.build(bld, bic)
224            self.do_build(bld, bic)
225
226    def do_defaults(self, variant):
227        return
228
229    def prepare_configure(self, conf, cic):
230        return
231
232    def do_configure(self, conf, cic):
233        return
234
235    def prepare_build(self, bld, bic):
236        return bic
237
238    def do_build(self, bld, bic):
239        return
240
241    def substitute(self, ctx, value):
242        if isinstance(value, str):
243            try:
244                return Template(value).substitute(EnvWrapper(ctx.env))
245            except Exception as e:
246                ctx.fatal(
247                    "In item '{}' substitution in '{}' failed: {}".format(
248                        self.uid, value, e
249                    )
250                )
251        return value
252
253    def get(self, ctx, name):
254        return self.substitute(ctx, self.data[name])
255
256    def get_values(self, ctx, name):
257        more = []
258        for value in self.data[name]:
259            more.extend(self.substitute(ctx, value).split())
260        return more
261
262    def install_target(self, bld):
263        install_path = self.data["install-path"]
264        if install_path:
265            bld.install_files(install_path, self.get(bld, "target"))
266
267    def install_files(self, bld):
268        for install in self.data["install"]:
269            bld.install_files(install["destination"], install["source"])
270
271    def asm(self, bld, bic, source, target=None):
272        if target is None:
273            target = os.path.splitext(source)[0] + ".o"
274        bld(
275            asflags=self.data["asflags"],
276            cppflags=self.data["cppflags"],
277            features="asm_explicit_target asm c",
278            includes=bic.includes + self.data["includes"],
279            source=[source],
280            target=target,
281        )
282        return target
283
284    def cc(self, bld, bic, source, target=None, deps=[], cppflags=[]):
285        if target is None:
286            target = os.path.splitext(source)[0] + ".o"
287        bld(
288            cflags=self.data["cflags"],
289            cppflags=cppflags + self.data["cppflags"],
290            features="c",
291            includes=bic.includes + self.data["includes"],
292            rule="${CC} ${CFLAGS} ${CPPFLAGS} ${DEFINES_ST:DEFINES} ${CPPPATH_ST:INCPATHS} -c ${SRC[0]} -o ${TGT}",
293            source=[source] + deps,
294            target=target,
295        )
296        return target
297
298    def cxx(self, bld, bic, source, target=None, deps=[], cppflags=[]):
299        if target is None:
300            target = os.path.splitext(source)[0] + ".o"
301        bld(
302            cppflags=cppflags + self.data["cppflags"],
303            cxxflags=self.data["cxxflags"],
304            features="cxx",
305            includes=bic.includes + self.data["includes"],
306            rule="${CXX} ${CXXFLAGS} ${CPPFLAGS} ${DEFINES_ST:DEFINES} ${CPPPATH_ST:INCPATHS} -c ${SRC[0]} -o ${TGT}",
307            source=[source] + deps,
308            target=target,
309        )
310        return target
311
312    def link(self, bld, bic, cmd, source, target):
313        from waflib.Task import Task
314
315        class link(Task):
316            def __init__(self, item, bic, cmd, env):
317                super(link, self).__init__(self, env=env)
318                self.cmd = cmd
319                self.ldflags = bic.ldflags + item.data["ldflags"]
320                self.stlib = item.data["stlib"]
321                self.use = (
322                    item.data["use-before"] + bic.use + item.data["use-after"]
323                )
324
325            def run(self):
326                cmd = [self.cmd]
327                cmd.extend(self.env.LINKFLAGS)
328                cmd.extend([i.abspath() for i in self.inputs])
329                cmd.append("-o" + self.outputs[0].abspath())
330                cmd.extend(self.ldflags)
331                cmd.append("-L.")
332                cmd.extend(["-l" + l for l in self.stlib])
333                cmd.extend(["-l" + l for l in self.use])
334                cmd.extend(self.env.LDFLAGS)
335                return self.exec_command(cmd)
336
337            def scan(self):
338                return (
339                    [
340                        self.generator.bld.bldnode.make_node("lib" + u + ".a")
341                        for u in self.use
342                    ],
343                    [],
344                )
345
346        tsk = link(self, bic, cmd, bld.env)
347        tsk.set_inputs([bld.bldnode.make_node(s) for s in source])
348        tsk.set_outputs(bld.bldnode.make_node(target))
349        bld.add_to_group(tsk)
350        return target
351
352    def link_cc(self, bld, bic, source, target):
353        return self.link(bld, bic, bld.env.LINK_CC[0], source, target)
354
355    def link_cxx(self, bld, bic, source, target):
356        return self.link(bld, bic, bld.env.LINK_CXX[0], source, target)
357
358    def gnatmake(self, bld, bic, objdir, objs, main, target):
359        from waflib.Task import Task
360
361        class gnatmake(Task):
362            def __init__(self, bld, bic, objdir, objs, main, target, item):
363                super(gnatmake, self).__init__(self, env=bld.env)
364                self.objdir = objdir
365                self.objs = [bld.bldnode.make_node(o) for o in objs]
366                self.main = bld.path.make_node(main)
367                self.set_inputs(self.objs + [self.main])
368                self.set_outputs(bld.bldnode.make_node(target))
369                self.adaflags = item.data["adaflags"]
370                self.adaincludes = []
371                for i in item.data["adaincludes"]:
372                    self.adaincludes.append(bld.bldnode.make_node(i))
373                    self.adaincludes.append(bld.path.make_node(i))
374                self.ldflags = bic.ldflags + item.data["ldflags"]
375                self.stlib = item.data["stlib"]
376                self.use = (
377                    item.data["use-before"] + bic.use + item.data["use-after"]
378                )
379
380            def run(self):
381                cwd = self.get_cwd()
382                cmd = [
383                    self.env.GNATMAKE[0],
384                    "-D",
385                    self.objdir,
386                    "-bargs",
387                    "-Mgnat_main",
388                    "-margs",
389                ]
390                cmd.extend(self.adaflags)
391                cmd.extend(["-I" + i.path_from(cwd) for i in self.adaincludes])
392                cmd.append("-largs")
393                cmd.extend([o.path_from(cwd) for o in self.objs])
394                cmd.extend(self.env.LINKFLAGS)
395                cmd.extend(self.ldflags)
396                cmd.append("-L.")
397                cmd.extend(["-l" + l for l in self.stlib])
398                cmd.extend(["-l" + l for l in self.use])
399                cmd.extend(self.env.LDFLAGS)
400                cmd.extend(["-margs", "-a"])
401                cmd.append(self.main.abspath())
402                cmd.append("-o")
403                cmd.append(self.outputs[0].abspath())
404                return self.exec_command(cmd)
405
406            def scan(self):
407                return (
408                    [
409                        self.generator.bld.bldnode.make_node("lib" + u + ".a")
410                        for u in self.use
411                    ],
412                    [],
413                )
414
415        tsk = gnatmake(bld, bic, objdir, objs, main, target, self)
416        bld.add_to_group(tsk)
417        return target
418
419    def ar(self, bld, source, target):
420        bld(rule="${AR} ${ARFLAGS} ${TGT} ${SRC}", source=source, target=target)
421        return target
422
423    def gzip(self, bld, source):
424        target = source + ".gz"
425        bld(rule="${GZIP} < ${SRC} > ${TGT}", source=source, target=target)
426        return target
427
428    def xz(self, bld, source):
429        target = source + ".xz"
430        bld(rule="${XZ} < ${SRC} > ${TGT}", source=source, target=target)
431        return target
432
433    def tar(self, bld, source, remove, target):
434        def run(task):
435            import tarfile
436
437            tar = tarfile.TarFile(
438                task.outputs[0].abspath(), "w", format=tarfile.USTAR_FORMAT
439            )
440            srcpath = bld.path.abspath() + "/"
441            bldpath = bld.bldnode.abspath() + "/"
442            for src in task.inputs:
443                src = src.abspath()
444                dst = src
445                for r in remove:
446                    dst = src.replace(srcpath + r, "").replace(bldpath + r, "")
447                tar.add(src, dst)
448            tar.close()
449            return 0
450
451        bld(rule=run, source=source, target=target)
452        return target
453
454    def bin2c(self, bld, source, name=None, target=None):
455        def run(task):
456            cmd = [bld.env.BIN2C[0]]
457            if name is not None:
458                cmd.extend(["-N", name])
459            cmd.append(task.inputs[0].abspath())
460            cmd.append(task.outputs[0].abspath())
461            return task.exec_command(cmd)
462
463        path, base = os.path.split(source)
464        if target is None:
465            target = path + "/" + base.replace(".", "-")
466        target_c = target + ".c"
467        target_h = target + ".h"
468        bld(rule=run, source=source, target=[target_c, target_h])
469        return target_c, target_h
470
471    def rtems_syms(self, bld, source, target):
472        bld(
473            rule='${RTEMS_SYMS} -e -C ${CC} -c "${CFLAGS}" -o ${TGT} ${SRC}',
474            source=source,
475            target=target,
476        )
477        return target
478
479    def rtems_rap(self, bld, base, objects, libs, target):
480        def run(task):
481            cmd = [
482                bld.env.RTEMS_LD[0],
483                "-C",
484                bld.env.CC[0],
485                "-c",
486                " ".join(bld.env.CFLAGS),
487                "-O",
488                "rap",
489                "-b",
490                task.inputs[0].abspath(),
491                "-e",
492                "rtems_main",
493                "-s",
494                "-o",
495            ]
496            cmd.append(task.outputs[0].abspath())
497            cmd.extend([i.abspath() for i in task.inputs[1:]])
498            cmd.extend(["-l" + l for l in libs])
499            return task.exec_command(cmd)
500
501        bld(rule=run, source=[base] + objects, target=target)
502        return target
503
504
505class GroupItem(Item):
506    def __init__(self, uid, data):
507        super(GroupItem, self).__init__(uid, data)
508
509    def prepare_build(self, bld, bic):
510        return BuildItemContext(
511            bic.includes + self.get_values(bld, "includes"),
512            self.data["use-before"] + bic.use + self.data["use-after"],
513            bic.ldflags + self.get_values(bld, "ldflags"),
514            bic.objects,
515        )
516
517    def do_build(self, bld, bic):
518        self.install_files(bld)
519
520
521class ConfigFileItem(Item):
522    def __init__(self, uid, data):
523        super(ConfigFileItem, self).__init__(uid, data)
524
525    def do_configure(self, conf, cic):
526        content = self.substitute(conf, self.data["content"])
527        f = conf.bldnode.make_node(
528            conf.env.VARIANT + "/" + self.get(conf, "target")
529        )
530        f.parent.mkdir()
531        f.write(content)
532        conf.env.append_value("cfg_files", f.abspath())
533
534    def do_build(self, bld, bic):
535        self.install_target(bld)
536
537
538class ConfigHeaderItem(Item):
539    def __init__(self, uid, data):
540        super(ConfigHeaderItem, self).__init__(uid, data)
541
542    def do_configure(self, conf, cic):
543        conf.env.include_key = self.data["include-headers"]
544        conf.write_config_header(
545            conf.env.VARIANT + "/" + self.get(conf, "target"),
546            guard=self.data["guard"],
547            headers=True,
548        )
549        conf.env.include_key = None
550
551    def do_build(self, bld, bic):
552        self.install_target(bld)
553
554
555class StartFileItem(Item):
556    def __init__(self, uid, data):
557        super(StartFileItem, self).__init__(uid, data)
558
559    def do_build(self, bld, bic):
560        tgt = self.asm(bld, bic, self.data["source"], self.get(bld, "target"))
561        node = bld.bldnode.make_node(tgt)
562        try:
563            bld.start_files.append(node)
564        except AttributeError:
565            bld.start_files = [node]
566        self.install_target(bld)
567
568
569class ObjectsItem(Item):
570    def __init__(self, uid, data):
571        super(ObjectsItem, self).__init__(uid, data)
572
573    def do_build(self, bld, bic):
574        bld.objects(
575            cflags=self.data["cflags"],
576            cppflags=self.data["cppflags"],
577            cxxflags=self.data["cxxflags"],
578            includes=bic.includes + self.data["includes"],
579            source=self.data["source"],
580            target=self.uid,
581        )
582        bic.objects.append(self.uid)
583        self.install_files(bld)
584
585
586class BSPItem(Item):
587    def __init__(self, uid, data):
588        super(BSPItem, self).__init__(uid, data)
589        arch_bsps = bsps.setdefault(data["arch"].strip(), {})
590        arch_bsps[data["bsp"].strip()] = self
591
592    def prepare_configure(self, conf, cic):
593        conf.env.BSP_FAMILY = self.data["family"]
594
595    def prepare_build(self, bld, bic):
596        return BuildItemContext(
597            bic.includes + bld.env.BSP_INCLUDES.split(), [], [], []
598        )
599
600    def do_build(self, bld, bic):
601        bld(
602            cflags=self.data["cflags"],
603            cppflags=self.data["cppflags"],
604            features="c cstlib",
605            includes=bic.includes + self.data["includes"],
606            install_path="${BSP_LIBDIR}",
607            source=self.data["source"],
608            target="rtemsbsp",
609            use=bic.objects,
610        )
611        self.install_files(bld)
612
613
614class LibraryItem(Item):
615    def __init__(self, uid, data):
616        super(LibraryItem, self).__init__(uid, data)
617
618    def prepare_build(self, bld, bic):
619        return BuildItemContext(bic.includes, [], [], [])
620
621    def do_build(self, bld, bic):
622        bld(
623            cflags=self.data["cflags"],
624            cppflags=self.data["cppflags"],
625            cxxflags=self.data["cxxflags"],
626            features="c cxx cstlib",
627            includes=bic.includes + self.data["includes"],
628            install_path=self.data["install-path"],
629            source=self.data["source"],
630            target=self.get(bld, "target"),
631            use=bic.objects,
632        )
633        self.install_files(bld)
634
635
636class TestProgramItem(Item):
637    def __init__(self, uid, data):
638        super(TestProgramItem, self).__init__(uid, data)
639        name = uid.split("/")[-1].upper().replace("-", "_")
640        self.exclude = "TEST_" + name + "_EXCLUDE"
641        self.cppflags = "TEST_" + name + "_CPPFLAGS"
642
643    def get_enabled_by(self):
644        return [{"and": [{"not": self.exclude}, self.data["enabled-by"]]}]
645
646    def prepare_build(self, bld, bic):
647        return BuildItemContext(bic.includes, bic.use, bic.ldflags, [])
648
649    def do_build(self, bld, bic):
650        bld(
651            cflags=self.data["cflags"],
652            cppflags=bld.env[self.cppflags] + self.data["cppflags"],
653            cxxflags=self.data["cxxflags"],
654            features=self.data["features"],
655            includes=bic.includes + self.data["includes"],
656            install_path=None,
657            ldflags=bic.ldflags + self.data["ldflags"],
658            source=self.data["source"],
659            start_files=True,
660            stlib=self.data["stlib"],
661            target=self.get(bld, "target"),
662            use=self.data["use-before"] + bic.use + self.data["use-after"],
663        )
664
665
666class AdaTestProgramItem(TestProgramItem):
667    def __init__(self, uid, data):
668        super(AdaTestProgramItem, self).__init__(uid, data)
669
670    def do_build(self, bld, bic):
671        objs = []
672        for s in self.data["source"]:
673            objs.append(self.cc(bld, bic, s))
674        self.gnatmake(
675            bld,
676            bic,
677            self.data["ada-object-directory"],
678            objs,
679            self.data["ada-main"],
680            self.data["target"],
681        )
682
683
684class OptionItem(Item):
685    def __init__(self, uid, data):
686        super(OptionItem, self).__init__(uid, data)
687
688    @staticmethod
689    def _is_variant(variants, variant):
690        for pattern in variants:
691            if re.search("^" + pattern + "$", variant):
692                return True
693        return False
694
695    def default_value(self, variant):
696        value = self.data["default"]
697        for default in self.data["default-by-variant"]:
698            if OptionItem._is_variant(default["variants"], variant):
699                value = default["value"]
700                break
701        if value is None:
702            return value
703        if isinstance(value, list):
704            return " ".join(value)
705        if isinstance(value, bool):
706            return value
707        return self.data["format"].format(value)
708
709    def do_defaults(self, variant):
710        value = self.default_value(variant)
711        if value is None:
712            return
713        description = self.data["description"]
714        if description:
715            import textwrap
716
717            tw = textwrap.TextWrapper()
718            tw.drop_whitespace = True
719            tw.initial_indent = "# "
720            tw.subsequent_indent = "# "
721            for line in tw.wrap(description):
722                print(line)
723        print("{} = {}".format(self.data["name"], value))
724
725    def _do_append_test_cppflags(self, conf, name, state):
726        conf.env.append_value("TEST_" + name.upper() + "_CPPFLAGS", state)
727
728    def _append_test_cppflags(self, conf, cic, value, arg):
729        self._do_append_test_cppflags(conf, arg, value)
730        return value
731
732    def _assert_aligned(self, conf, cic, value, arg):
733        if value % arg != 0:
734            conf.fatal(
735                "Value '{}' for option '{}' is not aligned by '{}'".format(
736                    value, self.data["name"], arg
737                )
738            )
739        return value
740
741    def _assert_eq(self, conf, cic, value, arg):
742        if value != arg:
743            conf.fatal(
744                "Value '{}' for option '{}' is not equal to {}".format(
745                    value, self.data["name"], arg
746                )
747            )
748        return value
749
750    def _assert_ge(self, conf, cic, value, arg):
751        if value < arg:
752            conf.fatal(
753                "Value '{}' for option '{}' is not greater than or equal to {}".format(
754                    value, self.data["name"], arg
755                )
756            )
757        return value
758
759    def _assert_gt(self, conf, cic, value, arg):
760        if value <= arg:
761            conf.fatal(
762                "Value '{}' for option '{}' is not greater than {}".format(
763                    value, self.data["name"], arg
764                )
765            )
766        return value
767
768    def _assert_in_interval(self, conf, cic, value, arg):
769        if value < arg[0] or value > arg[1]:
770            conf.fatal(
771                "Value '{}' for option '{}' is not in closed interval [{}, {}]".format(
772                    value, self.data["name"], arg[0], arg[1]
773                )
774            )
775        return value
776
777    def _assert_int8(self, conf, cic, value, arg):
778        return self._assert_in_interval(conf, cic, value, [-128, 127])
779
780    def _assert_int16(self, conf, cic, value, arg):
781        return self._assert_in_interval(conf, cic, value, [-32768, 32767])
782
783    def _assert_int32(self, conf, cic, value, arg):
784        return self._assert_in_interval(
785            conf, cic, value, [-2147483648, 2147483647]
786        )
787
788    def _assert_int64(self, conf, cic, value, arg):
789        return self._assert_in_interval(
790            conf, cic, value, [-9223372036854775808, 9223372036854775807]
791        )
792
793    def _assert_le(self, conf, cic, value, arg):
794        if value > arg:
795            conf.fatal(
796                "Value '{}' for option '{}' is not less than or equal to {}".format(
797                    value, self.data["name"], arg
798                )
799            )
800        return value
801
802    def _assert_lt(self, conf, cic, value, arg):
803        if value >= arg:
804            conf.fatal(
805                "Value '{}' for option '{}' is not less than {}".format(
806                    value, self.data["name"], arg
807                )
808            )
809        return value
810
811    def _assert_ne(self, conf, cic, value, arg):
812        if value == arg:
813            conf.fatal(
814                "Value '{}' for option '{}' is not unequal to {}".format(
815                    value, self.data["name"], arg
816                )
817            )
818        return value
819
820    def _assert_power_of_two(self, conf, cic, value, arg):
821        if value <= 0 or (value & (value - 1)) != 0:
822            conf.fatal(
823                "Value '{}' for option '{}' is not a power of two".format(
824                    value, self.data["name"]
825                )
826            )
827        return value
828
829    def _assert_uint8(self, conf, cic, value, arg):
830        return self._assert_in_interval(conf, cic, value, [0, 255])
831
832    def _assert_uint16(self, conf, cic, value, arg):
833        return self._assert_in_interval(conf, cic, value, [0, 65535])
834
835    def _assert_uint32(self, conf, cic, value, arg):
836        return self._assert_in_interval(conf, cic, value, [0, 4294967295])
837
838    def _assert_uint64(self, conf, cic, value, arg):
839        return self._assert_in_interval(
840            conf, cic, value, [0, 18446744073709551615]
841        )
842
843    def _check_cc(self, conf, cic, value, arg):
844        result = conf.check_cc(
845            fragment=arg["fragment"],
846            cflags=arg["cflags"],
847            msg="Checking for " + arg["message"],
848            mandatory=False,
849        )
850        return value and result
851
852    def _check_cxx(self, conf, cic, value, arg):
853        result = conf.check_cxx(
854            fragment=arg["fragment"],
855            cxxflags=arg["cxxflags"],
856            msg="Checking for " + arg["message"],
857            mandatory=False,
858        )
859        return value and result
860
861    def _define_condition(self, conf, cic, value, arg):
862        name = self.data["name"] if arg is None else arg
863        conf.define_cond(name, value)
864        return value
865
866    def _define(self, conf, cic, value, arg):
867        name = self.data["name"] if arg is None else arg
868        if value is not None:
869            conf.define(name, value)
870        else:
871            conf.define_cond(name, False)
872        return value
873
874    def _define_unquoted(self, conf, cic, value, arg):
875        name = self.data["name"] if arg is None else arg
876        if value is not None:
877            conf.define(name, value, quote=False)
878        else:
879            conf.define_cond(name, False)
880        return value
881
882    def _env_append(self, conf, cic, value, arg):
883        name = self.data["name"] if arg is None else arg
884        conf.env.append_value(name, value)
885        return value
886
887    def _env_assign(self, conf, cic, value, arg):
888        name = self.data["name"] if arg is None else arg
889        conf.env[name] = value
890        return value
891
892    def _env_enable(self, conf, cic, value, arg):
893        if value:
894            name = self.data["name"] if arg is None else arg
895            conf.env.append_value("ENABLE", name)
896        return value
897
898    def _find_program(self, conf, cic, value, arg):
899        return conf.find_program(value, path_list=cic.path_list)
900
901    def _format_and_define(self, conf, cic, value, arg):
902        name = self.data["name"] if arg is None else arg
903        if value is not None:
904            conf.define(name, self.data["format"].format(value), quote=False)
905        else:
906            conf.define_cond(name, False)
907        return value
908
909    def _get_boolean(self, conf, cic, value, arg):
910        name = self.data["name"]
911        try:
912            value = cic.cp.getboolean(conf.variant, name)
913            cic.add_option(name)
914        except configparser.NoOptionError:
915            value = self.default_value(conf.variant)
916        except ValueError as ve:
917            conf.fatal(
918                "Invalid value for configuration option {}: {}".format(name, ve)
919            )
920        return value
921
922    def _get_env(self, conf, cic, value, arg):
923        return conf.env[arg]
924
925    def _get_integer(self, conf, cic, value, arg):
926        name = self.data["name"]
927        try:
928            value = cic.cp.get(conf.variant, name)
929            cic.add_option(name)
930        except configparser.NoOptionError:
931            value = self.default_value(conf.variant)
932            if value is None:
933                return value
934        try:
935            return eval(value)
936        except Exception as e:
937            conf.fatal(
938                "Value '{}' for option '{}' is an invalid integer expression: {}".format(
939                    value, name, e
940                )
941            )
942
943    def _get_string(self, conf, cic, value, arg):
944        name = self.data["name"]
945        try:
946            value = cic.cp.get(conf.variant, name)
947            cic.add_option(name)
948            value = no_unicode(value)
949        except configparser.NoOptionError:
950            value = self.default_value(conf.variant)
951        return value
952
953    def _script(self, conf, cic, value, arg):
954        exec(arg)
955        return value
956
957    def _test_state_benchmark(self, conf, name):
958        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_BENCHMARK=1")
959
960    def _test_state_exclude(self, conf, name):
961        conf.env.append_value(
962            "ENABLE", "TEST_" + name.upper().replace("-", "_") + "_EXCLUDE"
963        )
964
965    def _test_state_expected_fail(self, conf, name):
966        self._do_append_test_cppflags(
967            conf, name, "-DTEST_STATE_EXPECTED_FAIL=1"
968        )
969
970    def _test_state_indeterminate(self, conf, name):
971        self._do_append_test_cppflags(
972            conf, name, "-DTEST_STATE_INDETERMINATE=1"
973        )
974
975    def _test_state_user_input(self, conf, name):
976        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_USER_INPUT=1")
977
978    def _set_test_state(self, conf, cic, value, arg):
979        actions = {
980            "benchmark": self._test_state_benchmark,
981            "exclude": self._test_state_exclude,
982            "expected-fail": self._test_state_expected_fail,
983            "indeterminate": self._test_state_indeterminate,
984            "user-input": self._test_state_user_input,
985        }
986        for k, v in arg.items():
987            actions[v](conf, k)
988        return value
989
990    def _set_value(self, conf, cic, value, arg):
991        return arg
992
993    def _split(self, conf, cic, value, arg):
994        return value.split()
995
996    def _substitute(self, conf, cic, value, arg):
997        if isinstance(value, list):
998            return [self.substitute(conf, v) for v in value]
999        else:
1000            return self.substitute(conf, value)
1001
1002    def do_configure(self, conf, cic):
1003        actions = {
1004            "append-test-cppflags": self._append_test_cppflags,
1005            "assert-aligned": self._assert_aligned,
1006            "assert-eq": self._assert_eq,
1007            "assert-ge": self._assert_ge,
1008            "assert-gt": self._assert_gt,
1009            "assert-int8": self._assert_int8,
1010            "assert-int16": self._assert_int16,
1011            "assert-int32": self._assert_int32,
1012            "assert-int64": self._assert_int64,
1013            "assert-le": self._assert_le,
1014            "assert-lt": self._assert_lt,
1015            "assert-ne": self._assert_ne,
1016            "assert-power-of-two": self._assert_power_of_two,
1017            "assert-uint8": self._assert_uint8,
1018            "assert-uint16": self._assert_uint16,
1019            "assert-uint32": self._assert_uint32,
1020            "assert-uint64": self._assert_uint64,
1021            "check-cc": self._check_cc,
1022            "check-cxx": self._check_cxx,
1023            "define-condition": self._define_condition,
1024            "define": self._define,
1025            "define-unquoted": self._define_unquoted,
1026            "env-append": self._env_append,
1027            "env-assign": self._env_assign,
1028            "env-enable": self._env_enable,
1029            "find-program": self._find_program,
1030            "format-and-define": self._format_and_define,
1031            "get-boolean": self._get_boolean,
1032            "get-env": self._get_env,
1033            "get-integer": self._get_integer,
1034            "get-string": self._get_string,
1035            "script": self._script,
1036            "set-test-state": self._set_test_state,
1037            "set-value": self._set_value,
1038            "split": self._split,
1039            "substitute": self._substitute,
1040        }
1041        value = None
1042        for action in self.data["actions"]:
1043            for action_arg in action.items():
1044                value = actions[action_arg[0]](conf, cic, value, action_arg[1])
1045
1046
1047class ScriptItem(Item):
1048    def __init__(self, uid, data):
1049        super(ScriptItem, self).__init__(uid, data)
1050
1051    def prepare_configure(self, conf, cic):
1052        script = self.data["prepare-configure"]
1053        if script:
1054            exec(script)
1055
1056    def do_configure(self, conf, cic):
1057        script = self.data["do-configure"]
1058        if script:
1059            exec(script)
1060
1061    def prepare_build(self, bld, bic):
1062        script = self.data["prepare-build"]
1063        if script:
1064            exec(script)
1065        return bic
1066
1067    def do_build(self, bld, bic):
1068        script = self.data["do-build"]
1069        if script:
1070            exec(script)
1071
1072
1073class ConfigItemContext(object):
1074    def __init__(self, cp, path_list):
1075        self.cp = cp
1076        self.options = set()
1077        self.path_list = path_list
1078
1079    def add_option(self, name):
1080        self.options.add(name.upper())
1081
1082
1083class BuildItemContext(object):
1084    def __init__(self, includes, use, ldflags, objects):
1085        self.includes = includes
1086        self.use = use
1087        self.ldflags = ldflags
1088        self.objects = objects
1089
1090
1091def is_one_item_newer(ctx, path, mtime):
1092    try:
1093        names = os.listdir(path)
1094    except Exception as e:
1095        ctx.fatal("Cannot list build specification directory: {}".format(e))
1096    for name in names:
1097        path2 = os.path.join(path, name)
1098        if name.endswith(".yml") and not name.startswith("."):
1099            mtime2 = os.path.getmtime(path2)
1100            if mtime <= mtime2:
1101                return True
1102        else:
1103            mode = os.lstat(path2).st_mode
1104            if stat.S_ISDIR(mode) and is_one_item_newer(ctx, path2, mtime):
1105                return True
1106    return False
1107
1108
1109def must_update_item_cache(ctx, path, cache_file):
1110    try:
1111        mtime = os.path.getmtime(cache_file)
1112        return is_one_item_newer(ctx, path, mtime)
1113    except:
1114        return True
1115
1116
1117def load_from_yaml(load, ctx, data_by_uid, base, path):
1118    try:
1119        names = os.listdir(path)
1120    except Exception as e:
1121        ctx.fatal("Cannot list build specification directory: {}".format(e))
1122    for name in names:
1123        path2 = os.path.join(path, name)
1124        if name.endswith(".yml") and not name.startswith("."):
1125            uid = "/" + os.path.relpath(path2, base).replace(".yml", "")
1126            with open(path2, "r") as f:
1127                data_by_uid[uid] = load(f.read())
1128        else:
1129            mode = os.lstat(path2).st_mode
1130            if stat.S_ISDIR(mode):
1131                load_from_yaml(load, ctx, data_by_uid, base, path2)
1132
1133
1134def load_items_in_directory(ctx, ctors, path):
1135    f = ctx.path.make_node(
1136        "build/c4che/" + re.sub(r"[^\w]", "_", path) + ".pickle"
1137    )
1138    f.parent.mkdir()
1139    cache_file = f.abspath()
1140    data_by_uid = {}
1141    if must_update_item_cache(ctx, path, cache_file):
1142        from waflib import Logs
1143
1144        Logs.warn(
1145            "Regenerate build specification cache (needs a couple of seconds)..."
1146        )
1147
1148        #
1149        # Do not use a system provided yaml module and instead import it from
1150        # the project.  This reduces the host system requirements to a simple
1151        # Python 2.7 or 3 installation without extra modules.
1152        #
1153        if sys.version_info[0] == 2:
1154            yaml_path = "yaml/lib"
1155        else:
1156            yaml_path = "yaml/lib3"
1157        sys.path += [yaml_path]
1158        from yaml import safe_load
1159
1160        load_from_yaml(safe_load, ctx, data_by_uid, path, path)
1161        with open(cache_file, "wb") as f:
1162            pickle.dump(data_by_uid, f)
1163    else:
1164        with open(cache_file, "rb") as f:
1165            data_by_uid = pickle.load(f)
1166    for uid, data in data_by_uid.items():
1167        if data["type"] == "build":
1168            items[uid] = ctors[data["build-type"]](uid, data)
1169
1170
1171def load_items(ctx, specs):
1172    if items:
1173        return
1174
1175    ctors = {
1176        "ada-test-program": AdaTestProgramItem,
1177        "bsp": BSPItem,
1178        "config-file": ConfigFileItem,
1179        "config-header": ConfigHeaderItem,
1180        "test-program": TestProgramItem,
1181        "group": GroupItem,
1182        "library": LibraryItem,
1183        "objects": ObjectsItem,
1184        "option": OptionItem,
1185        "script": ScriptItem,
1186        "start-file": StartFileItem,
1187    }
1188
1189    for path in specs:
1190        load_items_in_directory(ctx, ctors, path)
1191
1192
1193def load_items_from_options(ctx):
1194    specs = ctx.options.rtems_specs
1195    if specs is not None:
1196        specs = specs.split(",")
1197    else:
1198        specs = ["spec/build"]
1199    load_items(ctx, specs)
1200    return specs
1201
1202
1203def options(ctx):
1204    prefix = ctx.parser.get_option("--prefix")
1205    prefix.default = default_prefix
1206    prefix.help = "installation prefix [default: '{}']".format(default_prefix)
1207    rg = ctx.add_option_group("RTEMS options")
1208    rg.add_option(
1209        "--rtems-bsps",
1210        metavar="REGEX,...",
1211        help="a comma-separated list of Python regular expressions which select the desired BSP variants (e.g. 'sparc/erc32'); it may be used in the bsp_defaults and bsp_list commands",
1212    )
1213    rg.add_option(
1214        "--rtems-compiler",
1215        metavar="COMPILER",
1216        help="determines which compiler is used to list the BSP option defaults [default: 'gcc']; it may be used in the bsp_defaults command; valid compilers are: {}".format(
1217            ", ".join(compilers)
1218        ),
1219    )
1220    rg.add_option(
1221        "--rtems-config",
1222        metavar="CONFIG.INI,...",
1223        help="a comma-separated list of paths to the BSP configuration option files [default: 'config.ini']; default option values can be obtained via the bsp_defaults command; it may be used in the configure command",
1224    )
1225    rg.add_option(
1226        "--rtems-specs",
1227        metavar="SPECDIRS,...",
1228        help="a comma-separated list of directory paths to build specification items [default: 'spec/build']; it may be used in the bsp_defaults, bsp_list, and configure commands",
1229    )
1230    rg.add_option(
1231        "--rtems-tools",
1232        metavar="PREFIX,...",
1233        help="a comma-separated list of prefix paths to tools, e.g. compiler, linker, etc. [default: the installation prefix]; tools are searched in the prefix path and also in a 'bin' subdirectory of the prefix path; it may be used in the configure command",
1234    )
1235    rg.add_option(
1236        "--rtems-top-group",
1237        metavar="UID",
1238        help="the UID of the top-level group [default: '/grp']; it may be used in the bsp_defaults and configure commands",
1239    )
1240
1241
1242def check_environment(conf):
1243    for ev in [
1244        "AR",
1245        "AS",
1246        "ASFLAGS",
1247        "CC",
1248        "CFLAGS",
1249        "CPPFLAGS",
1250        "CXX",
1251        "CXXFLAGS",
1252        "IFLAGS",
1253        "LD",
1254        "LIB",
1255        "LINK_CC",
1256        "LINK_CXX",
1257        "LINKFLAGS",
1258        "MFLAGS",
1259        "RFLAGS",
1260        "WFLAGS",
1261    ]:
1262        if ev in os.environ:
1263            conf.msg("Environment variable set", ev, color="RED")
1264
1265
1266def load_config_files(ctx):
1267    cp = configparser.ConfigParser()
1268    files = ctx.options.rtems_config
1269    if files is not None:
1270        files = files.split(",")
1271    else:
1272        files = ["config.ini"]
1273    actual_files = cp.read(files)
1274    for o in files:
1275        if not o in actual_files:
1276            ctx.fatal("Option file '{}' was not readable".format(o))
1277    return cp
1278
1279
1280def inherit(conf, cp, bsp_map, arch, bsp, path):
1281    variant = arch + "/" + bsp
1282    if variant in path:
1283        path = " -> ".join(path + [variant])
1284        conf.fatal("Recursion in BSP options inheritance: {}".format(path))
1285
1286    try:
1287        base = cp.get(variant, "INHERIT")
1288        cp.remove_option(variant, "INHERIT")
1289        base = no_unicode(base)
1290        base_variant = arch + "/" + base
1291        conf.msg(
1292            "Inherit options from '{}'".format(base_variant),
1293            variant,
1294            color="YELLOW",
1295        )
1296        if not cp.has_section(base_variant):
1297            if (not arch in bsps) or (not base in bsps[arch]):
1298                conf.fatal(
1299                    "BSP variant '{}' cannot inherit options from not existing variant '{}'".format(
1300                        variant, base_variant
1301                    )
1302                )
1303            bsp_map[bsp] = base
1304            return base
1305        top = inherit(conf, cp, bsp_map, arch, base, path + [variant])
1306        for i in cp.items(base_variant):
1307            name = i[0]
1308            if not cp.has_option(variant, name):
1309                cp.set(variant, name, i[1])
1310        bsp_map[bsp] = top
1311        return top
1312    except configparser.NoOptionError:
1313        return bsp_map.get(bsp, bsp)
1314
1315
1316def resolve_option_inheritance(conf, cp):
1317    bsp_map = {}
1318    for variant in cp.sections():
1319        variant = no_unicode(variant)
1320        try:
1321            arch, bsp = variant.split("/")
1322        except:
1323            conf.fatal(
1324                "Section name '{}' is a malformed 'arch/bsp' tuple".format(
1325                    variant
1326                )
1327            )
1328        inherit(conf, cp, bsp_map, arch, bsp, [])
1329    return bsp_map
1330
1331
1332def check_compiler(ctx, compiler):
1333    if compiler not in compilers:
1334        ctx.fatal(
1335            "Specified compiler '{}' is not one of {}".format(
1336                compiler, compilers
1337            )
1338        )
1339
1340
1341def get_compiler(conf, cp, variant):
1342    try:
1343        value = cp.get(conf.variant, "COMPILER")
1344        cp.remove_option(conf.variant, "COMPILER")
1345        value = no_unicode(value)
1346        check_compiler(conf, value)
1347    except configparser.NoOptionError:
1348        value = "gcc"
1349    return value
1350
1351
1352def configure_variant(conf, cp, bsp_map, path_list, top_group, variant):
1353    conf.msg("Configure board support package (BSP)", variant, color="YELLOW")
1354
1355    conf.setenv(variant)
1356    arch, bsp_name = variant.split("/")
1357    bsp_base = bsp_map.get(bsp_name, bsp_name)
1358
1359    conf.env["ARCH"] = arch
1360    conf.env["BSP_BASE"] = bsp_base
1361    conf.env["BSP_NAME"] = bsp_name
1362    conf.env["DEST_OS"] = "rtems"
1363    conf.env["ENABLE"] = [get_compiler(conf, cp, variant), arch, variant]
1364    conf.env["TOP"] = conf.path.abspath()
1365    conf.env["TOPGROUP"] = top_group
1366    conf.env["VARIANT"] = variant
1367
1368    cic = ConfigItemContext(cp, path_list)
1369
1370    items[conf.env.TOPGROUP].configure(conf, cic)
1371
1372    try:
1373        bsp_item = bsps[arch][bsp_base]
1374    except KeyError:
1375        conf.fatal("No such base BSP: '{}'".format(variant))
1376    bsp_item.configure(conf, cic)
1377
1378    options = set([o[0].upper() for o in cp.items(variant)])
1379    for o in options.difference(cic.options):
1380        conf.msg("Unknown configuration option", o.upper(), color="RED")
1381
1382
1383def check_forbidden_options(ctx, opts):
1384    for o in opts:
1385        if getattr(ctx.options, "rtems_" + o):
1386            ctx.fatal(
1387                "The --rtems-{} command line option is not allowed in the {} command".format(
1388                    o.replace("_", "-"), ctx.cmd
1389                )
1390            )
1391
1392
1393def get_path_list(conf):
1394    path_list = []
1395    tools = conf.options.rtems_tools
1396    if tools is not None:
1397        for t in tools.split(","):
1398            path_list.extend([t + "/bin", t])
1399    path_list.append(conf.env.PREFIX + "/bin")
1400    path_list.extend(os.environ.get("PATH", "").split(os.pathsep))
1401    return path_list
1402
1403
1404def get_top_group(ctx):
1405    top_group = ctx.options.rtems_top_group
1406    if top_group is None:
1407        top_group = "/grp"
1408    if top_group not in items:
1409        ctx.fatal(
1410            "There is no top-level group with UID '{}' in the specification".format(
1411                top_group
1412            )
1413        )
1414    return top_group
1415
1416
1417def configure(conf):
1418    check_forbidden_options(conf, ["compiler"])
1419    check_environment(conf)
1420    conf.env["SPECS"] = load_items_from_options(conf)
1421    top_group = get_top_group(conf)
1422    cp = load_config_files(conf)
1423    bsp_map = resolve_option_inheritance(conf, cp)
1424    path_list = get_path_list(conf)
1425    variant_list = []
1426    for variant in cp.sections():
1427        variant = no_unicode(variant)
1428        variant_list.append(variant)
1429        configure_variant(conf, cp, bsp_map, path_list, top_group, variant)
1430    conf.setenv("")
1431    conf.env["VARIANTS"] = variant_list
1432
1433
1434def append_variant_builds(bld):
1435    import waflib.Options
1436    from waflib.Build import (
1437        BuildContext,
1438        CleanContext,
1439        InstallContext,
1440        UninstallContext,
1441    )
1442
1443    for var in bld.env["VARIANTS"]:
1444        for c in (BuildContext, CleanContext, InstallContext, UninstallContext):
1445            name = c.__name__.replace("Context", "").lower()
1446
1447            class magic(c):
1448                cmd = name + "_" + var
1449                variant = var
1450
1451        waflib.Options.commands.append(bld.cmd + "_" + var)
1452
1453
1454def long_command_line_workaround(bld):
1455    if is_windows_host:
1456        bld.load("long_gcc")
1457
1458
1459def build(bld):
1460    if not bld.variant:
1461        check_forbidden_options(
1462            bld, ["compiler", "config", "specs", "tools", "top_group"]
1463        )
1464        load_items(bld, bld.env.SPECS)
1465        append_variant_builds(bld)
1466        return
1467    long_command_line_workaround(bld)
1468    bic = BuildItemContext(bld.env.ARCH_INCLUDES.split(), [], [], [])
1469    bsps[bld.env.ARCH][bld.env.BSP_BASE].build(bld, bic)
1470    items[bld.env.TOPGROUP].build(bld, bic)
1471
1472
1473def add_log_filter(name):
1474    msg = "'" + name + "' finished successfully"
1475
1476    class Filter:
1477        def filter(self, rec):
1478            return not msg in rec.getMessage()
1479
1480    import logging
1481
1482    logging.getLogger("waflib").addFilter(Filter())
1483
1484
1485def get_white_list(ctx):
1486    white_list = ctx.options.rtems_bsps
1487    if white_list:
1488        white_list = white_list.split(",")
1489    return white_list
1490
1491
1492def is_in_white_list(variant, white_list):
1493    if not white_list:
1494        return True
1495    for pattern in white_list:
1496        if re.search(pattern, variant):
1497            return True
1498    return False
1499
1500
1501def no_matches_error(ctx, white_list):
1502    if white_list:
1503        ctx.fatal(
1504            "No BSP matches with the specified patterns: '{}'".format(
1505                "', '".join(white_list)
1506            )
1507        )
1508    else:
1509        ctx.fatal("The build specification contains no BSPs")
1510
1511
1512def bsp_defaults(ctx):
1513    """get all options with default values for base BSP variants"""
1514    check_forbidden_options(ctx, ["config", "tools"])
1515    add_log_filter(ctx.cmd)
1516    load_items_from_options(ctx)
1517    top_group = get_top_group(ctx)
1518    white_list = get_white_list(ctx)
1519    compiler = ctx.options.rtems_compiler
1520    if compiler is not None:
1521        check_compiler(ctx, compiler)
1522    else:
1523        compiler = "gcc"
1524    first = True
1525    for arch in sorted(bsps):
1526        for bsp in sorted(bsps[arch]):
1527            variant = arch + "/" + bsp
1528            if is_in_white_list(variant, white_list):
1529                if not first:
1530                    print("")
1531                first = False
1532                print(
1533                    """[{}]
1534# Selects the compiler used to build the BSP (allowed values are "gcc" and
1535# "clang").  Please note that the values of some options depend on the compiler
1536# selection and changing the compiler may lead to unpredictable behaviour if
1537# these options are not adjusted as well.  Use the --rtems-compiler command line
1538# option to get the default values for a particular compiler via
1539# ./waf bsp_defaults.
1540COMPILER = {}""".format(
1541                        variant, compiler
1542                    )
1543                )
1544                enable = [compiler, arch, variant]
1545                items[top_group].defaults(enable, variant)
1546                bsps[arch][bsp].defaults(enable, variant)
1547    if first:
1548        no_matches_error(ctx, white_list)
1549
1550
1551def bsp_list(ctx):
1552    """lists base BSP variants"""
1553    check_forbidden_options(ctx, ["compiler", "config", "tools", "top_group"])
1554    add_log_filter(ctx.cmd)
1555    load_items_from_options(ctx)
1556    white_list = get_white_list(ctx)
1557    first = True
1558    for arch in sorted(bsps):
1559        for bsp in sorted(bsps[arch]):
1560            variant = arch + "/" + bsp
1561            if is_in_white_list(variant, white_list):
1562                first = False
1563                print(variant)
1564    if first:
1565        no_matches_error(ctx, white_list)
Note: See TracBrowser for help on using the repository browser.