source: rtems/wscript @ dbb7c956

Last change on this file since dbb7c956 was ebdfa24b, checked in by Sebastian Huber <sebastian.huber@…>, on 07/23/21 at 06:45:07

build: Merge default-by-family into by-variant

Prefix the BSP family name with "bsps/" to make it distinct to the BSP
variant names.

Update #4468.

  • Property mode set to 100755
File size: 50.6 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, family):
207        if _is_enabled(enable, self.get_enabled_by()):
208            for p in self.links():
209                p.defaults(enable, variant, family)
210            self.do_defaults(variant, family)
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, family):
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.append("-L.")
331                cmd.extend(["-l" + l for l in self.stlib])
332                cmd.extend(["-l" + l for l in self.use])
333                cmd.extend(self.env.LDFLAGS)
334                cmd.extend(self.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("-cargs")
393                cmd.extend(self.env.ABI_FLAGS)
394                cmd.append("-largs")
395                cmd.extend([o.path_from(cwd) for o in self.objs])
396                cmd.extend(self.env.LINKFLAGS)
397                cmd.extend(self.ldflags)
398                cmd.append("-L.")
399                cmd.extend(["-l" + l for l in self.stlib])
400                cmd.extend(["-l" + l for l in self.use])
401                cmd.extend(self.env.LDFLAGS)
402                cmd.extend(["-margs", "-a"])
403                cmd.append(self.main.abspath())
404                cmd.append("-o")
405                cmd.append(self.outputs[0].abspath())
406                return self.exec_command(cmd)
407
408            def scan(self):
409                return (
410                    [
411                        self.generator.bld.bldnode.make_node("lib" + u + ".a")
412                        for u in self.use
413                    ],
414                    [],
415                )
416
417        tsk = gnatmake(bld, bic, objdir, objs, main, target, self)
418        bld.add_to_group(tsk)
419        return target
420
421    def ar(self, bld, source, target):
422        bld(rule="${AR} ${ARFLAGS} ${TGT} ${SRC}", source=source, target=target)
423        return target
424
425    def gzip(self, bld, source):
426        target = source + ".gz"
427        bld(rule="${GZIP} < ${SRC} > ${TGT}", source=source, target=target)
428        return target
429
430    def xz(self, bld, source):
431        target = source + ".xz"
432        bld(rule="${XZ} < ${SRC} > ${TGT}", source=source, target=target)
433        return target
434
435    def tar(self, bld, source, remove, target):
436        def run(task):
437            import tarfile
438
439            tar = tarfile.TarFile(
440                task.outputs[0].abspath(), "w", format=tarfile.USTAR_FORMAT
441            )
442            srcpath = bld.path.abspath() + "/"
443            bldpath = bld.bldnode.abspath() + "/"
444            for src in task.inputs:
445                src = src.abspath()
446                dst = src
447                for r in remove:
448                    dst = src.replace(srcpath + r, "").replace(bldpath + r, "")
449                tar.add(src, dst)
450            tar.close()
451            return 0
452
453        bld(rule=run, source=source, target=target)
454        return target
455
456    def bin2c(self, bld, source, name=None, target=None):
457        def run(task):
458            cmd = [bld.env.BIN2C[0]]
459            if name is not None:
460                cmd.extend(["-N", name])
461            cmd.append(task.inputs[0].abspath())
462            cmd.append(task.outputs[0].abspath())
463            return task.exec_command(cmd)
464
465        path, base = os.path.split(source)
466        if target is None:
467            target = path + "/" + base.replace(".", "-")
468        target_c = target + ".c"
469        target_h = target + ".h"
470        bld(rule=run, source=source, target=[target_c, target_h])
471        return target_c, target_h
472
473    def rtems_syms(self, bld, source, target):
474        bld(
475            rule='${RTEMS_SYMS} -e -C ${CC} -c "${CFLAGS}" -o ${TGT} ${SRC}',
476            source=source,
477            target=target,
478        )
479        return target
480
481    def rtems_rap(self, bld, base, objects, libs, target):
482        def run(task):
483            cmd = [
484                bld.env.RTEMS_LD[0],
485                "-C",
486                bld.env.CC[0],
487                "-c",
488                " ".join(bld.env.CFLAGS),
489                "-O",
490                "rap",
491                "-b",
492                task.inputs[0].abspath(),
493                "-e",
494                "rtems_main",
495                "-s",
496                "-o",
497            ]
498            cmd.append(task.outputs[0].abspath())
499            cmd.extend([i.abspath() for i in task.inputs[1:]])
500            cmd.extend(["-l" + l for l in libs])
501            return task.exec_command(cmd)
502
503        bld(rule=run, source=[base] + objects, target=target)
504        return target
505
506
507class GroupItem(Item):
508    def __init__(self, uid, data):
509        super(GroupItem, self).__init__(uid, data)
510
511    def prepare_build(self, bld, bic):
512        return BuildItemContext(
513            bic.includes + self.get_values(bld, "includes"),
514            self.data["use-before"] + bic.use + self.data["use-after"],
515            bic.ldflags + self.get_values(bld, "ldflags"),
516            bic.objects,
517        )
518
519    def do_build(self, bld, bic):
520        self.install_files(bld)
521
522
523class ConfigFileItem(Item):
524    def __init__(self, uid, data):
525        super(ConfigFileItem, self).__init__(uid, data)
526
527    def do_configure(self, conf, cic):
528        content = self.substitute(conf, self.data["content"])
529        f = conf.bldnode.make_node(
530            conf.env.VARIANT + "/" + self.get(conf, "target")
531        )
532        f.parent.mkdir()
533        f.write(content)
534        conf.env.append_value("cfg_files", f.abspath())
535
536    def do_build(self, bld, bic):
537        self.install_target(bld)
538
539
540class ConfigHeaderItem(Item):
541    def __init__(self, uid, data):
542        super(ConfigHeaderItem, self).__init__(uid, data)
543
544    def do_configure(self, conf, cic):
545        conf.env.include_key = self.data["include-headers"]
546        conf.write_config_header(
547            conf.env.VARIANT + "/" + self.get(conf, "target"),
548            guard=self.data["guard"],
549            headers=True,
550        )
551        conf.env.include_key = None
552
553    def do_build(self, bld, bic):
554        self.install_target(bld)
555
556
557class StartFileItem(Item):
558    def __init__(self, uid, data):
559        super(StartFileItem, self).__init__(uid, data)
560
561    def do_build(self, bld, bic):
562        tgt = self.asm(bld, bic, self.data["source"], self.get(bld, "target"))
563        node = bld.bldnode.make_node(tgt)
564        try:
565            bld.start_files.append(node)
566        except AttributeError:
567            bld.start_files = [node]
568        self.install_target(bld)
569
570
571class ObjectsItem(Item):
572    def __init__(self, uid, data):
573        super(ObjectsItem, self).__init__(uid, data)
574
575    def do_build(self, bld, bic):
576        bld.objects(
577            asflags=self.data["cppflags"],
578            cflags=self.data["cflags"],
579            cppflags=self.data["cppflags"],
580            cxxflags=self.data["cxxflags"],
581            includes=bic.includes + self.data["includes"],
582            source=self.data["source"],
583            target=self.uid,
584        )
585        bic.objects.append(self.uid)
586        self.install_files(bld)
587
588
589class BSPItem(Item):
590    def __init__(self, uid, data):
591        super(BSPItem, self).__init__(uid, data)
592        arch_bsps = bsps.setdefault(data["arch"].strip(), {})
593        arch_bsps[data["bsp"].strip()] = self
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=bic.objects + 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.match(pattern + "$", variant):
692                return True
693        return False
694
695    def default_value(self, variant, family):
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        else:
702            family = "bsps/" + family
703            for default in self.data["default-by-variant"]:
704                if OptionItem._is_variant(default["variants"], family):
705                    value = default["value"]
706                    break
707        if value is None:
708            return value
709        if isinstance(value, list):
710            return " ".join(value)
711        if isinstance(value, bool):
712            return value
713        return self.data["format"].format(value)
714
715    def do_defaults(self, variant, family):
716        value = self.default_value(variant, family)
717        if value is None:
718            return
719        description = self.data["description"]
720        if description:
721            import textwrap
722
723            tw = textwrap.TextWrapper()
724            tw.drop_whitespace = True
725            tw.initial_indent = "# "
726            tw.subsequent_indent = "# "
727            for line in tw.wrap(description):
728                print(line)
729        print("{} = {}".format(self.data["name"], value))
730
731    def _do_append_test_cppflags(self, conf, name, state):
732        conf.env.append_value(
733            "TEST_" + name.upper().replace("-", "_") + "_CPPFLAGS", state
734        )
735
736    def _append_test_cppflags(self, conf, cic, value, arg):
737        self._do_append_test_cppflags(conf, arg, value)
738        return value
739
740    def _assert_aligned(self, conf, cic, value, arg):
741        if value % arg != 0:
742            conf.fatal(
743                "Value '{}' for option '{}' is not aligned by '{}'".format(
744                    value, self.data["name"], arg
745                )
746            )
747        return value
748
749    def _assert_eq(self, conf, cic, value, arg):
750        if value != arg:
751            conf.fatal(
752                "Value '{}' for option '{}' is not equal to {}".format(
753                    value, self.data["name"], arg
754                )
755            )
756        return value
757
758    def _assert_ge(self, conf, cic, value, arg):
759        if value < arg:
760            conf.fatal(
761                "Value '{}' for option '{}' is not greater than or equal to {}".format(
762                    value, self.data["name"], arg
763                )
764            )
765        return value
766
767    def _assert_gt(self, conf, cic, value, arg):
768        if value <= arg:
769            conf.fatal(
770                "Value '{}' for option '{}' is not greater than {}".format(
771                    value, self.data["name"], arg
772                )
773            )
774        return value
775
776    def _assert_in_interval(self, conf, cic, value, arg):
777        if value < arg[0] or value > arg[1]:
778            conf.fatal(
779                "Value '{}' for option '{}' is not in closed interval [{}, {}]".format(
780                    value, self.data["name"], arg[0], arg[1]
781                )
782            )
783        return value
784
785    def _assert_int8(self, conf, cic, value, arg):
786        return self._assert_in_interval(conf, cic, value, [-128, 127])
787
788    def _assert_int16(self, conf, cic, value, arg):
789        return self._assert_in_interval(conf, cic, value, [-32768, 32767])
790
791    def _assert_int32(self, conf, cic, value, arg):
792        return self._assert_in_interval(
793            conf, cic, value, [-2147483648, 2147483647]
794        )
795
796    def _assert_int64(self, conf, cic, value, arg):
797        return self._assert_in_interval(
798            conf, cic, value, [-9223372036854775808, 9223372036854775807]
799        )
800
801    def _assert_le(self, conf, cic, value, arg):
802        if value > arg:
803            conf.fatal(
804                "Value '{}' for option '{}' is not less than or equal to {}".format(
805                    value, self.data["name"], arg
806                )
807            )
808        return value
809
810    def _assert_lt(self, conf, cic, value, arg):
811        if value >= arg:
812            conf.fatal(
813                "Value '{}' for option '{}' is not less than {}".format(
814                    value, self.data["name"], arg
815                )
816            )
817        return value
818
819    def _assert_ne(self, conf, cic, value, arg):
820        if value == arg:
821            conf.fatal(
822                "Value '{}' for option '{}' is not unequal to {}".format(
823                    value, self.data["name"], arg
824                )
825            )
826        return value
827
828    def _assert_power_of_two(self, conf, cic, value, arg):
829        if value <= 0 or (value & (value - 1)) != 0:
830            conf.fatal(
831                "Value '{}' for option '{}' is not a power of two".format(
832                    value, self.data["name"]
833                )
834            )
835        return value
836
837    def _assert_uint8(self, conf, cic, value, arg):
838        return self._assert_in_interval(conf, cic, value, [0, 255])
839
840    def _assert_uint16(self, conf, cic, value, arg):
841        return self._assert_in_interval(conf, cic, value, [0, 65535])
842
843    def _assert_uint32(self, conf, cic, value, arg):
844        return self._assert_in_interval(conf, cic, value, [0, 4294967295])
845
846    def _assert_uint64(self, conf, cic, value, arg):
847        return self._assert_in_interval(
848            conf, cic, value, [0, 18446744073709551615]
849        )
850
851    def _check_cc(self, conf, cic, value, arg):
852        result = conf.check_cc(
853            fragment=arg["fragment"],
854            cflags=arg["cflags"],
855            msg="Checking for " + arg["message"],
856            mandatory=False,
857        )
858        return value and result
859
860    def _check_cxx(self, conf, cic, value, arg):
861        result = conf.check_cxx(
862            fragment=arg["fragment"],
863            cxxflags=arg["cxxflags"],
864            msg="Checking for " + arg["message"],
865            mandatory=False,
866        )
867        return value and result
868
869    def _define_condition(self, conf, cic, value, arg):
870        name = self.data["name"] if arg is None else arg
871        conf.define_cond(name, value)
872        return value
873
874    def _define(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)
878        else:
879            conf.define_cond(name, False)
880        return value
881
882    def _define_unquoted(self, conf, cic, value, arg):
883        name = self.data["name"] if arg is None else arg
884        if value is not None:
885            conf.define(name, value, quote=False)
886        else:
887            conf.define_cond(name, False)
888        return value
889
890    def _env_append(self, conf, cic, value, arg):
891        name = self.data["name"] if arg is None else arg
892        conf.env.append_value(name, value)
893        return value
894
895    def _env_assign(self, conf, cic, value, arg):
896        name = self.data["name"] if arg is None else arg
897        conf.env[name] = value
898        return value
899
900    def _env_enable(self, conf, cic, value, arg):
901        if value:
902            name = self.data["name"] if arg is None else arg
903            conf.env.append_value("ENABLE", name)
904        return value
905
906    def _find_program(self, conf, cic, value, arg):
907        return conf.find_program(value, path_list=cic.path_list)
908
909    def _format_and_define(self, conf, cic, value, arg):
910        name = self.data["name"] if arg is None else arg
911        if value is not None:
912            conf.define(name, self.data["format"].format(value), quote=False)
913        else:
914            conf.define_cond(name, False)
915        return value
916
917    def _get_boolean(self, conf, cic, value, arg):
918        name = self.data["name"]
919        try:
920            value = cic.cp.getboolean(conf.variant, name)
921            cic.add_option(name)
922        except configparser.NoOptionError:
923            value = self.default_value(conf.env.ARCH_BSP, conf.env.ARCH_FAMILY)
924        except ValueError as ve:
925            conf.fatal(
926                "Invalid value for configuration option {}: {}".format(name, ve)
927            )
928        return value
929
930    def _get_env(self, conf, cic, value, arg):
931        return conf.env[arg]
932
933    def _get_integer(self, conf, cic, value, arg):
934        name = self.data["name"]
935        try:
936            value = cic.cp.get(conf.variant, name)
937            cic.add_option(name)
938        except configparser.NoOptionError:
939            value = self.default_value(conf.env.ARCH_BSP, conf.env.ARCH_FAMILY)
940            if value is None:
941                return value
942        try:
943            return eval(value)
944        except Exception as e:
945            conf.fatal(
946                "Value '{}' for option '{}' is an invalid integer expression: {}".format(
947                    value, name, e
948                )
949            )
950
951    def _get_string(self, conf, cic, value, arg):
952        name = self.data["name"]
953        try:
954            value = cic.cp.get(conf.variant, name)
955            cic.add_option(name)
956            value = no_unicode(value)
957        except configparser.NoOptionError:
958            value = self.default_value(conf.env.ARCH_BSP, conf.env.ARCH_FAMILY)
959        return value
960
961    def _script(self, conf, cic, value, arg):
962        exec(arg)
963        return value
964
965    def _test_state_benchmark(self, conf, name):
966        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_BENCHMARK=1")
967
968    def _test_state_exclude(self, conf, name):
969        conf.env.append_value(
970            "ENABLE", "TEST_" + name.upper().replace("-", "_") + "_EXCLUDE"
971        )
972
973    def _test_state_expected_fail(self, conf, name):
974        self._do_append_test_cppflags(
975            conf, name, "-DTEST_STATE_EXPECTED_FAIL=1"
976        )
977
978    def _test_state_indeterminate(self, conf, name):
979        self._do_append_test_cppflags(
980            conf, name, "-DTEST_STATE_INDETERMINATE=1"
981        )
982
983    def _test_state_user_input(self, conf, name):
984        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_USER_INPUT=1")
985
986    def _set_test_state(self, conf, cic, value, arg):
987        actions = {
988            "benchmark": self._test_state_benchmark,
989            "exclude": self._test_state_exclude,
990            "expected-fail": self._test_state_expected_fail,
991            "indeterminate": self._test_state_indeterminate,
992            "user-input": self._test_state_user_input,
993        }
994        for k, v in arg.items():
995            actions[v](conf, k)
996        return value
997
998    def _set_value(self, conf, cic, value, arg):
999        return arg
1000
1001    def _split(self, conf, cic, value, arg):
1002        return value.split()
1003
1004    def _substitute(self, conf, cic, value, arg):
1005        if isinstance(value, list):
1006            return [self.substitute(conf, v) for v in value]
1007        else:
1008            return self.substitute(conf, value)
1009
1010    def do_configure(self, conf, cic):
1011        actions = {
1012            "append-test-cppflags": self._append_test_cppflags,
1013            "assert-aligned": self._assert_aligned,
1014            "assert-eq": self._assert_eq,
1015            "assert-ge": self._assert_ge,
1016            "assert-gt": self._assert_gt,
1017            "assert-int8": self._assert_int8,
1018            "assert-int16": self._assert_int16,
1019            "assert-int32": self._assert_int32,
1020            "assert-int64": self._assert_int64,
1021            "assert-le": self._assert_le,
1022            "assert-lt": self._assert_lt,
1023            "assert-ne": self._assert_ne,
1024            "assert-power-of-two": self._assert_power_of_two,
1025            "assert-uint8": self._assert_uint8,
1026            "assert-uint16": self._assert_uint16,
1027            "assert-uint32": self._assert_uint32,
1028            "assert-uint64": self._assert_uint64,
1029            "check-cc": self._check_cc,
1030            "check-cxx": self._check_cxx,
1031            "define-condition": self._define_condition,
1032            "define": self._define,
1033            "define-unquoted": self._define_unquoted,
1034            "env-append": self._env_append,
1035            "env-assign": self._env_assign,
1036            "env-enable": self._env_enable,
1037            "find-program": self._find_program,
1038            "format-and-define": self._format_and_define,
1039            "get-boolean": self._get_boolean,
1040            "get-env": self._get_env,
1041            "get-integer": self._get_integer,
1042            "get-string": self._get_string,
1043            "script": self._script,
1044            "set-test-state": self._set_test_state,
1045            "set-value": self._set_value,
1046            "split": self._split,
1047            "substitute": self._substitute,
1048        }
1049        value = None
1050        for action in self.data["actions"]:
1051            for action_arg in action.items():
1052                value = actions[action_arg[0]](conf, cic, value, action_arg[1])
1053
1054
1055class ScriptItem(Item):
1056    def __init__(self, uid, data):
1057        super(ScriptItem, self).__init__(uid, data)
1058
1059    def prepare_configure(self, conf, cic):
1060        script = self.data["prepare-configure"]
1061        if script:
1062            exec(script)
1063
1064    def do_configure(self, conf, cic):
1065        script = self.data["do-configure"]
1066        if script:
1067            exec(script)
1068
1069    def prepare_build(self, bld, bic):
1070        script = self.data["prepare-build"]
1071        if script:
1072            exec(script)
1073        return bic
1074
1075    def do_build(self, bld, bic):
1076        script = self.data["do-build"]
1077        if script:
1078            exec(script)
1079
1080
1081class ConfigItemContext(object):
1082    def __init__(self, cp, path_list):
1083        self.cp = cp
1084        self.options = set()
1085        self.path_list = path_list
1086
1087    def add_option(self, name):
1088        self.options.add(name.upper())
1089
1090
1091class BuildItemContext(object):
1092    def __init__(self, includes, use, ldflags, objects):
1093        self.includes = includes
1094        self.use = use
1095        self.ldflags = ldflags
1096        self.objects = objects
1097
1098
1099def is_one_item_newer(ctx, path, mtime):
1100    try:
1101        mtime2 = os.path.getmtime(path)
1102        if mtime <= mtime2:
1103            return True
1104        names = os.listdir(path)
1105    except Exception as e:
1106        ctx.fatal("Cannot access build specification directory: {}".format(e))
1107    for name in names:
1108        path2 = os.path.join(path, name)
1109        if name.endswith(".yml") and not name.startswith("."):
1110            mtime2 = os.path.getmtime(path2)
1111            if mtime <= mtime2:
1112                return True
1113        else:
1114            mode = os.lstat(path2).st_mode
1115            if stat.S_ISDIR(mode) and is_one_item_newer(ctx, path2, mtime):
1116                return True
1117    return False
1118
1119
1120def must_update_item_cache(ctx, path, cache_file):
1121    try:
1122        mtime = os.path.getmtime(cache_file)
1123    except:
1124        return True
1125    return is_one_item_newer(ctx, path, mtime)
1126
1127
1128def load_from_yaml(load, ctx, data_by_uid, base, path):
1129    try:
1130        names = os.listdir(path)
1131    except Exception as e:
1132        ctx.fatal("Cannot list build specification directory: {}".format(e))
1133    for name in names:
1134        path2 = os.path.join(path, name)
1135        if name.endswith(".yml") and not name.startswith("."):
1136            uid = "/" + os.path.relpath(path2, base).replace(".yml", "")
1137            with open(path2, "r") as f:
1138                data_by_uid[uid] = load(f.read())
1139        else:
1140            mode = os.lstat(path2).st_mode
1141            if stat.S_ISDIR(mode):
1142                load_from_yaml(load, ctx, data_by_uid, base, path2)
1143
1144
1145def load_items_in_directory(ctx, ctors, path):
1146    p = "c4che/" + re.sub(r"[^\w]", "_", path) + ".pickle"
1147    try:
1148        f = ctx.bldnode.make_node(p)
1149    except AttributeError:
1150        f = ctx.path.make_node("build/" + p)
1151    f.parent.mkdir()
1152    cache_file = f.abspath()
1153    data_by_uid = {}
1154    if must_update_item_cache(ctx, path, cache_file):
1155        from waflib import Logs
1156
1157        Logs.warn(
1158            "Regenerate build specification cache (needs a couple of seconds)..."
1159        )
1160
1161        #
1162        # Do not use a system provided yaml module and instead import it from
1163        # the project.  This reduces the host system requirements to a simple
1164        # Python 2.7 or 3 installation without extra modules.
1165        #
1166        if sys.version_info[0] == 2:
1167            yaml_path = "yaml/lib"
1168        else:
1169            yaml_path = "yaml/lib3"
1170        sys.path += [yaml_path]
1171        from yaml import safe_load
1172
1173        load_from_yaml(safe_load, ctx, data_by_uid, path, path)
1174        with open(cache_file, "wb") as f:
1175            pickle.dump(data_by_uid, f)
1176    else:
1177        with open(cache_file, "rb") as f:
1178            data_by_uid = pickle.load(f)
1179    for uid, data in data_by_uid.items():
1180        if data["type"] == "build":
1181            items[uid] = ctors[data["build-type"]](uid, data)
1182
1183
1184def load_items(ctx, specs):
1185    if items:
1186        return
1187
1188    ctors = {
1189        "ada-test-program": AdaTestProgramItem,
1190        "bsp": BSPItem,
1191        "config-file": ConfigFileItem,
1192        "config-header": ConfigHeaderItem,
1193        "test-program": TestProgramItem,
1194        "group": GroupItem,
1195        "library": LibraryItem,
1196        "objects": ObjectsItem,
1197        "option": OptionItem,
1198        "script": ScriptItem,
1199        "start-file": StartFileItem,
1200    }
1201
1202    for path in specs:
1203        load_items_in_directory(ctx, ctors, path)
1204
1205
1206def load_items_from_options(ctx):
1207    specs = ctx.options.rtems_specs
1208    if specs is not None:
1209        specs = specs.split(",")
1210    else:
1211        specs = ["spec/build"]
1212    load_items(ctx, specs)
1213    return specs
1214
1215
1216def options(ctx):
1217    prefix = ctx.parser.get_option("--prefix")
1218    prefix.default = default_prefix
1219    prefix.help = "installation prefix [default: '{}']".format(default_prefix)
1220    rg = ctx.add_option_group("RTEMS options")
1221    rg.add_option(
1222        "--rtems-bsps",
1223        metavar="REGEX,...",
1224        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",
1225    )
1226    rg.add_option(
1227        "--rtems-compiler",
1228        metavar="COMPILER",
1229        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(
1230            ", ".join(compilers)
1231        ),
1232    )
1233    rg.add_option(
1234        "--rtems-config",
1235        metavar="CONFIG.INI,...",
1236        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",
1237    )
1238    rg.add_option(
1239        "--rtems-specs",
1240        metavar="SPECDIRS,...",
1241        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",
1242    )
1243    rg.add_option(
1244        "--rtems-tools",
1245        metavar="PREFIX,...",
1246        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",
1247    )
1248    rg.add_option(
1249        "--rtems-top-group",
1250        metavar="UID",
1251        help="the UID of the top-level group [default: '/grp']; it may be used in the bsp_defaults and configure commands",
1252    )
1253
1254
1255def check_environment(conf):
1256    for ev in [
1257        "AR",
1258        "AS",
1259        "ASFLAGS",
1260        "CC",
1261        "CFLAGS",
1262        "CPPFLAGS",
1263        "CXX",
1264        "CXXFLAGS",
1265        "IFLAGS",
1266        "LD",
1267        "LIB",
1268        "LINK_CC",
1269        "LINK_CXX",
1270        "LINKFLAGS",
1271        "MFLAGS",
1272        "RFLAGS",
1273        "WFLAGS",
1274    ]:
1275        if ev in os.environ:
1276            conf.msg("Environment variable set", ev, color="RED")
1277
1278
1279def load_config_files(ctx):
1280    cp = configparser.ConfigParser()
1281    files = ctx.options.rtems_config
1282    if files is not None:
1283        files = files.split(",")
1284    else:
1285        files = ["config.ini"]
1286    actual_files = cp.read(files)
1287    for o in files:
1288        if not o in actual_files:
1289            ctx.fatal("Option file '{}' was not readable".format(o))
1290    return cp
1291
1292
1293def inherit(conf, cp, bsp_map, arch, bsp, path):
1294    variant = arch + "/" + bsp
1295    if variant in path:
1296        path = " -> ".join(path + [variant])
1297        conf.fatal("Recursion in BSP options inheritance: {}".format(path))
1298
1299    try:
1300        base = cp.get(variant, "INHERIT")
1301        cp.remove_option(variant, "INHERIT")
1302        base = no_unicode(base)
1303        base_variant = arch + "/" + base
1304        conf.msg(
1305            "Inherit options from '{}'".format(base_variant),
1306            variant,
1307            color="YELLOW",
1308        )
1309        if not cp.has_section(base_variant):
1310            if (not arch in bsps) or (not base in bsps[arch]):
1311                conf.fatal(
1312                    "BSP variant '{}' cannot inherit options from not existing variant '{}'".format(
1313                        variant, base_variant
1314                    )
1315                )
1316            bsp_map[bsp] = base
1317            return base
1318        top = inherit(conf, cp, bsp_map, arch, base, path + [variant])
1319        for i in cp.items(base_variant):
1320            name = i[0]
1321            if not cp.has_option(variant, name):
1322                cp.set(variant, name, i[1])
1323        bsp_map[bsp] = top
1324        return top
1325    except configparser.NoOptionError:
1326        return bsp_map.get(bsp, bsp)
1327
1328
1329def resolve_option_inheritance(conf, cp):
1330    bsp_map = {}
1331    for variant in cp.sections():
1332        variant = no_unicode(variant)
1333        try:
1334            arch, bsp = variant.split("/")
1335        except:
1336            conf.fatal(
1337                "Section name '{}' is a malformed 'arch/bsp' tuple".format(
1338                    variant
1339                )
1340            )
1341        inherit(conf, cp, bsp_map, arch, bsp, [])
1342    return bsp_map
1343
1344
1345def check_compiler(ctx, compiler):
1346    if compiler not in compilers:
1347        ctx.fatal(
1348            "Specified compiler '{}' is not one of {}".format(
1349                compiler, compilers
1350            )
1351        )
1352
1353
1354def get_compiler(conf, cp, variant):
1355    try:
1356        value = cp.get(variant, "COMPILER")
1357        cp.remove_option(variant, "COMPILER")
1358        value = no_unicode(value)
1359        check_compiler(conf, value)
1360    except configparser.NoOptionError:
1361        value = "gcc"
1362    return value
1363
1364
1365def configure_variant(conf, cp, bsp_map, path_list, top_group, variant):
1366    conf.msg("Configure board support package (BSP)", variant, color="YELLOW")
1367
1368    conf.setenv(variant)
1369    arch, bsp_name = variant.split("/")
1370    bsp_base = bsp_map.get(bsp_name, bsp_name)
1371
1372    try:
1373        bsp_item = bsps[arch][bsp_base]
1374    except KeyError:
1375        conf.fatal("No such base BSP: '{}'".format(variant))
1376
1377    family = bsp_item.data["family"]
1378
1379    arch_bsp = arch + "/" + bsp_base
1380    arch_family = arch + "/" + family
1381
1382    conf.env["ARCH"] = arch
1383    conf.env["ARCH_BSP"] = arch_bsp
1384    conf.env["ARCH_FAMILY"] = arch_family
1385    conf.env["BSP_BASE"] = bsp_base
1386    conf.env["BSP_NAME"] = bsp_name
1387    conf.env["BSP_FAMILY"] = family
1388    conf.env["DEST_OS"] = "rtems"
1389
1390    # For the enabled-by evaluation we have to use the base BSP defined by the
1391    # build specification and not the BSP name provided by the user.
1392    conf.env["ENABLE"] = [
1393        get_compiler(conf, cp, variant),
1394        arch,
1395        "bsps/" + arch_family,
1396        arch_bsp,
1397    ]
1398
1399    conf.env["TOP"] = conf.path.abspath()
1400    conf.env["TOPGROUP"] = top_group
1401    conf.env["VARIANT"] = variant
1402
1403    cic = ConfigItemContext(cp, path_list)
1404
1405    items[conf.env.TOPGROUP].configure(conf, cic)
1406
1407    bsp_item.configure(conf, cic)
1408
1409    options = set([o[0].upper() for o in cp.items(variant)])
1410    for o in options.difference(cic.options):
1411        conf.msg("Unknown configuration option", o.upper(), color="RED")
1412
1413
1414def check_forbidden_options(ctx, opts):
1415    for o in opts:
1416        if getattr(ctx.options, "rtems_" + o):
1417            ctx.fatal(
1418                "The --rtems-{} command line option is not allowed in the {} command".format(
1419                    o.replace("_", "-"), ctx.cmd
1420                )
1421            )
1422
1423
1424def get_path_list(conf):
1425    path_list = []
1426    tools = conf.options.rtems_tools
1427    if tools is not None:
1428        for t in tools.split(","):
1429            path_list.extend([t + "/bin", t])
1430    path_list.append(conf.env.PREFIX + "/bin")
1431    path_list.extend(os.environ.get("PATH", "").split(os.pathsep))
1432    return path_list
1433
1434
1435def get_top_group(ctx):
1436    top_group = ctx.options.rtems_top_group
1437    if top_group is None:
1438        top_group = "/grp"
1439    if top_group not in items:
1440        ctx.fatal(
1441            "There is no top-level group with UID '{}' in the specification".format(
1442                top_group
1443            )
1444        )
1445    return top_group
1446
1447
1448def configure(conf):
1449    check_forbidden_options(conf, ["compiler"])
1450    check_environment(conf)
1451    conf.env["SPECS"] = load_items_from_options(conf)
1452    top_group = get_top_group(conf)
1453    cp = load_config_files(conf)
1454    bsp_map = resolve_option_inheritance(conf, cp)
1455    path_list = get_path_list(conf)
1456    variant_list = []
1457    for variant in cp.sections():
1458        variant = no_unicode(variant)
1459        variant_list.append(variant)
1460        configure_variant(conf, cp, bsp_map, path_list, top_group, variant)
1461    conf.setenv("")
1462    conf.env["VARIANTS"] = variant_list
1463
1464
1465def append_variant_builds(bld):
1466    import waflib.Options
1467    from waflib.Build import (
1468        BuildContext,
1469        CleanContext,
1470        InstallContext,
1471        UninstallContext,
1472    )
1473
1474    for var in bld.env["VARIANTS"]:
1475        for c in (BuildContext, CleanContext, InstallContext, UninstallContext):
1476            name = c.__name__.replace("Context", "").lower()
1477
1478            class magic(c):
1479                cmd = name + "_" + var
1480                variant = var
1481
1482        waflib.Options.commands.append(bld.cmd + "_" + var)
1483
1484
1485def long_command_line_workaround(bld):
1486    if is_windows_host:
1487        bld.load("long_gcc")
1488
1489
1490def build(bld):
1491    if not bld.variant:
1492        check_forbidden_options(
1493            bld, ["compiler", "config", "specs", "tools", "top_group"]
1494        )
1495        load_items(bld, bld.env.SPECS)
1496        append_variant_builds(bld)
1497        return
1498    long_command_line_workaround(bld)
1499    bic = BuildItemContext(bld.env.ARCH_INCLUDES.split(), [], [], [])
1500    bsps[bld.env.ARCH][bld.env.BSP_BASE].build(bld, bic)
1501    items[bld.env.TOPGROUP].build(bld, bic)
1502
1503
1504def add_log_filter(name):
1505    msg = "'" + name + "' finished successfully"
1506
1507    class Filter:
1508        def filter(self, rec):
1509            return not msg in rec.getMessage()
1510
1511    import logging
1512
1513    logging.getLogger("waflib").addFilter(Filter())
1514
1515
1516def get_white_list(ctx):
1517    white_list = ctx.options.rtems_bsps
1518    if white_list:
1519        white_list = white_list.split(",")
1520    return white_list
1521
1522
1523def is_in_white_list(variant, white_list):
1524    if not white_list:
1525        return True
1526    for pattern in white_list:
1527        if re.match(pattern + "$", variant):
1528            return True
1529    return False
1530
1531
1532def no_matches_error(ctx, white_list):
1533    if white_list:
1534        ctx.fatal(
1535            "No BSP matches with the specified patterns: '{}'".format(
1536                "', '".join(white_list)
1537            )
1538        )
1539    else:
1540        ctx.fatal("The build specification contains no BSPs")
1541
1542
1543def bsp_defaults(ctx):
1544    """get all options with default values for base BSP variants"""
1545    check_forbidden_options(ctx, ["config", "tools"])
1546    add_log_filter(ctx.cmd)
1547    load_items_from_options(ctx)
1548    top_group = get_top_group(ctx)
1549    white_list = get_white_list(ctx)
1550    compiler = ctx.options.rtems_compiler
1551    if compiler is not None:
1552        check_compiler(ctx, compiler)
1553    else:
1554        compiler = "gcc"
1555    first = True
1556    for arch in sorted(bsps):
1557        for bsp in sorted(bsps[arch]):
1558            variant = arch + "/" + bsp
1559            if is_in_white_list(variant, white_list):
1560                if not first:
1561                    print("")
1562                first = False
1563                print(
1564                    """[{}]
1565# Selects the compiler used to build the BSP (allowed values are "gcc" and
1566# "clang").  Please note that the values of some options depend on the compiler
1567# selection and changing the compiler may lead to unpredictable behaviour if
1568# these options are not adjusted as well.  Use the --rtems-compiler command line
1569# option to get the default values for a particular compiler via
1570# ./waf bsp_defaults.
1571COMPILER = {}""".format(
1572                        variant, compiler
1573                    )
1574                )
1575                enable = [compiler, arch, variant]
1576                bsp_item = bsps[arch][bsp]
1577                family = arch + "/" + bsp_item.data["family"]
1578                items[top_group].defaults(enable, variant, family)
1579                bsp_item.defaults(enable, variant, family)
1580    if first:
1581        no_matches_error(ctx, white_list)
1582
1583
1584def bsp_list(ctx):
1585    """lists base BSP variants"""
1586    check_forbidden_options(ctx, ["compiler", "config", "tools", "top_group"])
1587    add_log_filter(ctx.cmd)
1588    load_items_from_options(ctx)
1589    white_list = get_white_list(ctx)
1590    first = True
1591    for arch in sorted(bsps):
1592        for bsp in sorted(bsps[arch]):
1593            variant = arch + "/" + bsp
1594            if is_in_white_list(variant, white_list):
1595                first = False
1596                print(variant)
1597    if first:
1598        no_matches_error(ctx, white_list)
Note: See TracBrowser for help on using the repository browser.