source: rtems/wscript @ b361eabd

Last change on this file since b361eabd was 9d2db27a, checked in by Sebastian Huber <sebastian.huber@…>, on 01/05/21 at 09:45:28

build: Add CPPFLAGS to assembler command line

We use GCC to call the assembler. This means the assembler files are
processed by the C preprocessor.

  • Property mode set to 100755
File size: 50.0 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("-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_configure(self, conf, cic):
596        conf.env.BSP_FAMILY = self.data["family"]
597
598    def prepare_build(self, bld, bic):
599        return BuildItemContext(
600            bic.includes + bld.env.BSP_INCLUDES.split(), [], [], []
601        )
602
603    def do_build(self, bld, bic):
604        bld(
605            cflags=self.data["cflags"],
606            cppflags=self.data["cppflags"],
607            features="c cstlib",
608            includes=bic.includes + self.data["includes"],
609            install_path="${BSP_LIBDIR}",
610            source=self.data["source"],
611            target="rtemsbsp",
612            use=bic.objects,
613        )
614        self.install_files(bld)
615
616
617class LibraryItem(Item):
618    def __init__(self, uid, data):
619        super(LibraryItem, self).__init__(uid, data)
620
621    def prepare_build(self, bld, bic):
622        return BuildItemContext(bic.includes, [], [], [])
623
624    def do_build(self, bld, bic):
625        bld(
626            cflags=self.data["cflags"],
627            cppflags=self.data["cppflags"],
628            cxxflags=self.data["cxxflags"],
629            features="c cxx cstlib",
630            includes=bic.includes + self.data["includes"],
631            install_path=self.data["install-path"],
632            source=self.data["source"],
633            target=self.get(bld, "target"),
634            use=bic.objects,
635        )
636        self.install_files(bld)
637
638
639class TestProgramItem(Item):
640    def __init__(self, uid, data):
641        super(TestProgramItem, self).__init__(uid, data)
642        name = uid.split("/")[-1].upper().replace("-", "_")
643        self.exclude = "TEST_" + name + "_EXCLUDE"
644        self.cppflags = "TEST_" + name + "_CPPFLAGS"
645
646    def get_enabled_by(self):
647        return [{"and": [{"not": self.exclude}, self.data["enabled-by"]]}]
648
649    def prepare_build(self, bld, bic):
650        return BuildItemContext(bic.includes, bic.use, bic.ldflags, [])
651
652    def do_build(self, bld, bic):
653        bld(
654            cflags=self.data["cflags"],
655            cppflags=bld.env[self.cppflags] + self.data["cppflags"],
656            cxxflags=self.data["cxxflags"],
657            features=self.data["features"],
658            includes=bic.includes + self.data["includes"],
659            install_path=None,
660            ldflags=bic.ldflags + self.data["ldflags"],
661            source=self.data["source"],
662            start_files=True,
663            stlib=self.data["stlib"],
664            target=self.get(bld, "target"),
665            use=self.data["use-before"] + bic.use + self.data["use-after"],
666        )
667
668
669class AdaTestProgramItem(TestProgramItem):
670    def __init__(self, uid, data):
671        super(AdaTestProgramItem, self).__init__(uid, data)
672
673    def do_build(self, bld, bic):
674        objs = []
675        for s in self.data["source"]:
676            objs.append(self.cc(bld, bic, s))
677        self.gnatmake(
678            bld,
679            bic,
680            self.data["ada-object-directory"],
681            objs,
682            self.data["ada-main"],
683            self.data["target"],
684        )
685
686
687class OptionItem(Item):
688    def __init__(self, uid, data):
689        super(OptionItem, self).__init__(uid, data)
690
691    @staticmethod
692    def _is_variant(variants, variant):
693        for pattern in variants:
694            if re.match(pattern + "$", variant):
695                return True
696        return False
697
698    def default_value(self, variant):
699        value = self.data["default"]
700        for default in self.data["default-by-variant"]:
701            if OptionItem._is_variant(default["variants"], variant):
702                value = default["value"]
703                break
704        if value is None:
705            return value
706        if isinstance(value, list):
707            return " ".join(value)
708        if isinstance(value, bool):
709            return value
710        return self.data["format"].format(value)
711
712    def do_defaults(self, variant):
713        value = self.default_value(variant)
714        if value is None:
715            return
716        description = self.data["description"]
717        if description:
718            import textwrap
719
720            tw = textwrap.TextWrapper()
721            tw.drop_whitespace = True
722            tw.initial_indent = "# "
723            tw.subsequent_indent = "# "
724            for line in tw.wrap(description):
725                print(line)
726        print("{} = {}".format(self.data["name"], value))
727
728    def _do_append_test_cppflags(self, conf, name, state):
729        conf.env.append_value("TEST_" + name.upper().replace("-", "_") + "_CPPFLAGS", state)
730
731    def _append_test_cppflags(self, conf, cic, value, arg):
732        self._do_append_test_cppflags(conf, arg, value)
733        return value
734
735    def _assert_aligned(self, conf, cic, value, arg):
736        if value % arg != 0:
737            conf.fatal(
738                "Value '{}' for option '{}' is not aligned by '{}'".format(
739                    value, self.data["name"], arg
740                )
741            )
742        return value
743
744    def _assert_eq(self, conf, cic, value, arg):
745        if value != arg:
746            conf.fatal(
747                "Value '{}' for option '{}' is not equal to {}".format(
748                    value, self.data["name"], arg
749                )
750            )
751        return value
752
753    def _assert_ge(self, conf, cic, value, arg):
754        if value < arg:
755            conf.fatal(
756                "Value '{}' for option '{}' is not greater than or equal to {}".format(
757                    value, self.data["name"], arg
758                )
759            )
760        return value
761
762    def _assert_gt(self, conf, cic, value, arg):
763        if value <= arg:
764            conf.fatal(
765                "Value '{}' for option '{}' is not greater than {}".format(
766                    value, self.data["name"], arg
767                )
768            )
769        return value
770
771    def _assert_in_interval(self, conf, cic, value, arg):
772        if value < arg[0] or value > arg[1]:
773            conf.fatal(
774                "Value '{}' for option '{}' is not in closed interval [{}, {}]".format(
775                    value, self.data["name"], arg[0], arg[1]
776                )
777            )
778        return value
779
780    def _assert_int8(self, conf, cic, value, arg):
781        return self._assert_in_interval(conf, cic, value, [-128, 127])
782
783    def _assert_int16(self, conf, cic, value, arg):
784        return self._assert_in_interval(conf, cic, value, [-32768, 32767])
785
786    def _assert_int32(self, conf, cic, value, arg):
787        return self._assert_in_interval(
788            conf, cic, value, [-2147483648, 2147483647]
789        )
790
791    def _assert_int64(self, conf, cic, value, arg):
792        return self._assert_in_interval(
793            conf, cic, value, [-9223372036854775808, 9223372036854775807]
794        )
795
796    def _assert_le(self, conf, cic, value, arg):
797        if value > arg:
798            conf.fatal(
799                "Value '{}' for option '{}' is not less than or equal to {}".format(
800                    value, self.data["name"], arg
801                )
802            )
803        return value
804
805    def _assert_lt(self, conf, cic, value, arg):
806        if value >= arg:
807            conf.fatal(
808                "Value '{}' for option '{}' is not less than {}".format(
809                    value, self.data["name"], arg
810                )
811            )
812        return value
813
814    def _assert_ne(self, conf, cic, value, arg):
815        if value == arg:
816            conf.fatal(
817                "Value '{}' for option '{}' is not unequal to {}".format(
818                    value, self.data["name"], arg
819                )
820            )
821        return value
822
823    def _assert_power_of_two(self, conf, cic, value, arg):
824        if value <= 0 or (value & (value - 1)) != 0:
825            conf.fatal(
826                "Value '{}' for option '{}' is not a power of two".format(
827                    value, self.data["name"]
828                )
829            )
830        return value
831
832    def _assert_uint8(self, conf, cic, value, arg):
833        return self._assert_in_interval(conf, cic, value, [0, 255])
834
835    def _assert_uint16(self, conf, cic, value, arg):
836        return self._assert_in_interval(conf, cic, value, [0, 65535])
837
838    def _assert_uint32(self, conf, cic, value, arg):
839        return self._assert_in_interval(conf, cic, value, [0, 4294967295])
840
841    def _assert_uint64(self, conf, cic, value, arg):
842        return self._assert_in_interval(
843            conf, cic, value, [0, 18446744073709551615]
844        )
845
846    def _check_cc(self, conf, cic, value, arg):
847        result = conf.check_cc(
848            fragment=arg["fragment"],
849            cflags=arg["cflags"],
850            msg="Checking for " + arg["message"],
851            mandatory=False,
852        )
853        return value and result
854
855    def _check_cxx(self, conf, cic, value, arg):
856        result = conf.check_cxx(
857            fragment=arg["fragment"],
858            cxxflags=arg["cxxflags"],
859            msg="Checking for " + arg["message"],
860            mandatory=False,
861        )
862        return value and result
863
864    def _define_condition(self, conf, cic, value, arg):
865        name = self.data["name"] if arg is None else arg
866        conf.define_cond(name, value)
867        return value
868
869    def _define(self, conf, cic, value, arg):
870        name = self.data["name"] if arg is None else arg
871        if value is not None:
872            conf.define(name, value)
873        else:
874            conf.define_cond(name, False)
875        return value
876
877    def _define_unquoted(self, conf, cic, value, arg):
878        name = self.data["name"] if arg is None else arg
879        if value is not None:
880            conf.define(name, value, quote=False)
881        else:
882            conf.define_cond(name, False)
883        return value
884
885    def _env_append(self, conf, cic, value, arg):
886        name = self.data["name"] if arg is None else arg
887        conf.env.append_value(name, value)
888        return value
889
890    def _env_assign(self, conf, cic, value, arg):
891        name = self.data["name"] if arg is None else arg
892        conf.env[name] = value
893        return value
894
895    def _env_enable(self, conf, cic, value, arg):
896        if value:
897            name = self.data["name"] if arg is None else arg
898            conf.env.append_value("ENABLE", name)
899        return value
900
901    def _find_program(self, conf, cic, value, arg):
902        return conf.find_program(value, path_list=cic.path_list)
903
904    def _format_and_define(self, conf, cic, value, arg):
905        name = self.data["name"] if arg is None else arg
906        if value is not None:
907            conf.define(name, self.data["format"].format(value), quote=False)
908        else:
909            conf.define_cond(name, False)
910        return value
911
912    def _get_boolean(self, conf, cic, value, arg):
913        name = self.data["name"]
914        try:
915            value = cic.cp.getboolean(conf.variant, name)
916            cic.add_option(name)
917        except configparser.NoOptionError:
918            value = self.default_value(conf.env.ARCH_BSP)
919        except ValueError as ve:
920            conf.fatal(
921                "Invalid value for configuration option {}: {}".format(name, ve)
922            )
923        return value
924
925    def _get_env(self, conf, cic, value, arg):
926        return conf.env[arg]
927
928    def _get_integer(self, conf, cic, value, arg):
929        name = self.data["name"]
930        try:
931            value = cic.cp.get(conf.variant, name)
932            cic.add_option(name)
933        except configparser.NoOptionError:
934            value = self.default_value(conf.env.ARCH_BSP)
935            if value is None:
936                return value
937        try:
938            return eval(value)
939        except Exception as e:
940            conf.fatal(
941                "Value '{}' for option '{}' is an invalid integer expression: {}".format(
942                    value, name, e
943                )
944            )
945
946    def _get_string(self, conf, cic, value, arg):
947        name = self.data["name"]
948        try:
949            value = cic.cp.get(conf.variant, name)
950            cic.add_option(name)
951            value = no_unicode(value)
952        except configparser.NoOptionError:
953            value = self.default_value(conf.env.ARCH_BSP)
954        return value
955
956    def _script(self, conf, cic, value, arg):
957        exec(arg)
958        return value
959
960    def _test_state_benchmark(self, conf, name):
961        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_BENCHMARK=1")
962
963    def _test_state_exclude(self, conf, name):
964        conf.env.append_value(
965            "ENABLE", "TEST_" + name.upper().replace("-", "_") + "_EXCLUDE"
966        )
967
968    def _test_state_expected_fail(self, conf, name):
969        self._do_append_test_cppflags(
970            conf, name, "-DTEST_STATE_EXPECTED_FAIL=1"
971        )
972
973    def _test_state_indeterminate(self, conf, name):
974        self._do_append_test_cppflags(
975            conf, name, "-DTEST_STATE_INDETERMINATE=1"
976        )
977
978    def _test_state_user_input(self, conf, name):
979        self._do_append_test_cppflags(conf, name, "-DTEST_STATE_USER_INPUT=1")
980
981    def _set_test_state(self, conf, cic, value, arg):
982        actions = {
983            "benchmark": self._test_state_benchmark,
984            "exclude": self._test_state_exclude,
985            "expected-fail": self._test_state_expected_fail,
986            "indeterminate": self._test_state_indeterminate,
987            "user-input": self._test_state_user_input,
988        }
989        for k, v in arg.items():
990            actions[v](conf, k)
991        return value
992
993    def _set_value(self, conf, cic, value, arg):
994        return arg
995
996    def _split(self, conf, cic, value, arg):
997        return value.split()
998
999    def _substitute(self, conf, cic, value, arg):
1000        if isinstance(value, list):
1001            return [self.substitute(conf, v) for v in value]
1002        else:
1003            return self.substitute(conf, value)
1004
1005    def do_configure(self, conf, cic):
1006        actions = {
1007            "append-test-cppflags": self._append_test_cppflags,
1008            "assert-aligned": self._assert_aligned,
1009            "assert-eq": self._assert_eq,
1010            "assert-ge": self._assert_ge,
1011            "assert-gt": self._assert_gt,
1012            "assert-int8": self._assert_int8,
1013            "assert-int16": self._assert_int16,
1014            "assert-int32": self._assert_int32,
1015            "assert-int64": self._assert_int64,
1016            "assert-le": self._assert_le,
1017            "assert-lt": self._assert_lt,
1018            "assert-ne": self._assert_ne,
1019            "assert-power-of-two": self._assert_power_of_two,
1020            "assert-uint8": self._assert_uint8,
1021            "assert-uint16": self._assert_uint16,
1022            "assert-uint32": self._assert_uint32,
1023            "assert-uint64": self._assert_uint64,
1024            "check-cc": self._check_cc,
1025            "check-cxx": self._check_cxx,
1026            "define-condition": self._define_condition,
1027            "define": self._define,
1028            "define-unquoted": self._define_unquoted,
1029            "env-append": self._env_append,
1030            "env-assign": self._env_assign,
1031            "env-enable": self._env_enable,
1032            "find-program": self._find_program,
1033            "format-and-define": self._format_and_define,
1034            "get-boolean": self._get_boolean,
1035            "get-env": self._get_env,
1036            "get-integer": self._get_integer,
1037            "get-string": self._get_string,
1038            "script": self._script,
1039            "set-test-state": self._set_test_state,
1040            "set-value": self._set_value,
1041            "split": self._split,
1042            "substitute": self._substitute,
1043        }
1044        value = None
1045        for action in self.data["actions"]:
1046            for action_arg in action.items():
1047                value = actions[action_arg[0]](conf, cic, value, action_arg[1])
1048
1049
1050class ScriptItem(Item):
1051    def __init__(self, uid, data):
1052        super(ScriptItem, self).__init__(uid, data)
1053
1054    def prepare_configure(self, conf, cic):
1055        script = self.data["prepare-configure"]
1056        if script:
1057            exec(script)
1058
1059    def do_configure(self, conf, cic):
1060        script = self.data["do-configure"]
1061        if script:
1062            exec(script)
1063
1064    def prepare_build(self, bld, bic):
1065        script = self.data["prepare-build"]
1066        if script:
1067            exec(script)
1068        return bic
1069
1070    def do_build(self, bld, bic):
1071        script = self.data["do-build"]
1072        if script:
1073            exec(script)
1074
1075
1076class ConfigItemContext(object):
1077    def __init__(self, cp, path_list):
1078        self.cp = cp
1079        self.options = set()
1080        self.path_list = path_list
1081
1082    def add_option(self, name):
1083        self.options.add(name.upper())
1084
1085
1086class BuildItemContext(object):
1087    def __init__(self, includes, use, ldflags, objects):
1088        self.includes = includes
1089        self.use = use
1090        self.ldflags = ldflags
1091        self.objects = objects
1092
1093
1094def is_one_item_newer(ctx, path, mtime):
1095    try:
1096        mtime2 = os.path.getmtime(path)
1097        if mtime <= mtime2:
1098            return True
1099        names = os.listdir(path)
1100    except Exception as e:
1101        ctx.fatal("Cannot access build specification directory: {}".format(e))
1102    for name in names:
1103        path2 = os.path.join(path, name)
1104        if name.endswith(".yml") and not name.startswith("."):
1105            mtime2 = os.path.getmtime(path2)
1106            if mtime <= mtime2:
1107                return True
1108        else:
1109            mode = os.lstat(path2).st_mode
1110            if stat.S_ISDIR(mode) and is_one_item_newer(ctx, path2, mtime):
1111                return True
1112    return False
1113
1114
1115def must_update_item_cache(ctx, path, cache_file):
1116    try:
1117        mtime = os.path.getmtime(cache_file)
1118    except:
1119        return True
1120    return is_one_item_newer(ctx, path, mtime)
1121
1122
1123def load_from_yaml(load, ctx, data_by_uid, base, path):
1124    try:
1125        names = os.listdir(path)
1126    except Exception as e:
1127        ctx.fatal("Cannot list build specification directory: {}".format(e))
1128    for name in names:
1129        path2 = os.path.join(path, name)
1130        if name.endswith(".yml") and not name.startswith("."):
1131            uid = "/" + os.path.relpath(path2, base).replace(".yml", "")
1132            with open(path2, "r") as f:
1133                data_by_uid[uid] = load(f.read())
1134        else:
1135            mode = os.lstat(path2).st_mode
1136            if stat.S_ISDIR(mode):
1137                load_from_yaml(load, ctx, data_by_uid, base, path2)
1138
1139
1140def load_items_in_directory(ctx, ctors, path):
1141    p = "c4che/" + re.sub(r"[^\w]", "_", path) + ".pickle"
1142    try:
1143        f = ctx.bldnode.make_node(p)
1144    except AttributeError:
1145        f = ctx.path.make_node("build/" + p)
1146    f.parent.mkdir()
1147    cache_file = f.abspath()
1148    data_by_uid = {}
1149    if must_update_item_cache(ctx, path, cache_file):
1150        from waflib import Logs
1151
1152        Logs.warn(
1153            "Regenerate build specification cache (needs a couple of seconds)..."
1154        )
1155
1156        #
1157        # Do not use a system provided yaml module and instead import it from
1158        # the project.  This reduces the host system requirements to a simple
1159        # Python 2.7 or 3 installation without extra modules.
1160        #
1161        if sys.version_info[0] == 2:
1162            yaml_path = "yaml/lib"
1163        else:
1164            yaml_path = "yaml/lib3"
1165        sys.path += [yaml_path]
1166        from yaml import safe_load
1167
1168        load_from_yaml(safe_load, ctx, data_by_uid, path, path)
1169        with open(cache_file, "wb") as f:
1170            pickle.dump(data_by_uid, f)
1171    else:
1172        with open(cache_file, "rb") as f:
1173            data_by_uid = pickle.load(f)
1174    for uid, data in data_by_uid.items():
1175        if data["type"] == "build":
1176            items[uid] = ctors[data["build-type"]](uid, data)
1177
1178
1179def load_items(ctx, specs):
1180    if items:
1181        return
1182
1183    ctors = {
1184        "ada-test-program": AdaTestProgramItem,
1185        "bsp": BSPItem,
1186        "config-file": ConfigFileItem,
1187        "config-header": ConfigHeaderItem,
1188        "test-program": TestProgramItem,
1189        "group": GroupItem,
1190        "library": LibraryItem,
1191        "objects": ObjectsItem,
1192        "option": OptionItem,
1193        "script": ScriptItem,
1194        "start-file": StartFileItem,
1195    }
1196
1197    for path in specs:
1198        load_items_in_directory(ctx, ctors, path)
1199
1200
1201def load_items_from_options(ctx):
1202    specs = ctx.options.rtems_specs
1203    if specs is not None:
1204        specs = specs.split(",")
1205    else:
1206        specs = ["spec/build"]
1207    load_items(ctx, specs)
1208    return specs
1209
1210
1211def options(ctx):
1212    prefix = ctx.parser.get_option("--prefix")
1213    prefix.default = default_prefix
1214    prefix.help = "installation prefix [default: '{}']".format(default_prefix)
1215    rg = ctx.add_option_group("RTEMS options")
1216    rg.add_option(
1217        "--rtems-bsps",
1218        metavar="REGEX,...",
1219        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",
1220    )
1221    rg.add_option(
1222        "--rtems-compiler",
1223        metavar="COMPILER",
1224        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(
1225            ", ".join(compilers)
1226        ),
1227    )
1228    rg.add_option(
1229        "--rtems-config",
1230        metavar="CONFIG.INI,...",
1231        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",
1232    )
1233    rg.add_option(
1234        "--rtems-specs",
1235        metavar="SPECDIRS,...",
1236        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",
1237    )
1238    rg.add_option(
1239        "--rtems-tools",
1240        metavar="PREFIX,...",
1241        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",
1242    )
1243    rg.add_option(
1244        "--rtems-top-group",
1245        metavar="UID",
1246        help="the UID of the top-level group [default: '/grp']; it may be used in the bsp_defaults and configure commands",
1247    )
1248
1249
1250def check_environment(conf):
1251    for ev in [
1252        "AR",
1253        "AS",
1254        "ASFLAGS",
1255        "CC",
1256        "CFLAGS",
1257        "CPPFLAGS",
1258        "CXX",
1259        "CXXFLAGS",
1260        "IFLAGS",
1261        "LD",
1262        "LIB",
1263        "LINK_CC",
1264        "LINK_CXX",
1265        "LINKFLAGS",
1266        "MFLAGS",
1267        "RFLAGS",
1268        "WFLAGS",
1269    ]:
1270        if ev in os.environ:
1271            conf.msg("Environment variable set", ev, color="RED")
1272
1273
1274def load_config_files(ctx):
1275    cp = configparser.ConfigParser()
1276    files = ctx.options.rtems_config
1277    if files is not None:
1278        files = files.split(",")
1279    else:
1280        files = ["config.ini"]
1281    actual_files = cp.read(files)
1282    for o in files:
1283        if not o in actual_files:
1284            ctx.fatal("Option file '{}' was not readable".format(o))
1285    return cp
1286
1287
1288def inherit(conf, cp, bsp_map, arch, bsp, path):
1289    variant = arch + "/" + bsp
1290    if variant in path:
1291        path = " -> ".join(path + [variant])
1292        conf.fatal("Recursion in BSP options inheritance: {}".format(path))
1293
1294    try:
1295        base = cp.get(variant, "INHERIT")
1296        cp.remove_option(variant, "INHERIT")
1297        base = no_unicode(base)
1298        base_variant = arch + "/" + base
1299        conf.msg(
1300            "Inherit options from '{}'".format(base_variant),
1301            variant,
1302            color="YELLOW",
1303        )
1304        if not cp.has_section(base_variant):
1305            if (not arch in bsps) or (not base in bsps[arch]):
1306                conf.fatal(
1307                    "BSP variant '{}' cannot inherit options from not existing variant '{}'".format(
1308                        variant, base_variant
1309                    )
1310                )
1311            bsp_map[bsp] = base
1312            return base
1313        top = inherit(conf, cp, bsp_map, arch, base, path + [variant])
1314        for i in cp.items(base_variant):
1315            name = i[0]
1316            if not cp.has_option(variant, name):
1317                cp.set(variant, name, i[1])
1318        bsp_map[bsp] = top
1319        return top
1320    except configparser.NoOptionError:
1321        return bsp_map.get(bsp, bsp)
1322
1323
1324def resolve_option_inheritance(conf, cp):
1325    bsp_map = {}
1326    for variant in cp.sections():
1327        variant = no_unicode(variant)
1328        try:
1329            arch, bsp = variant.split("/")
1330        except:
1331            conf.fatal(
1332                "Section name '{}' is a malformed 'arch/bsp' tuple".format(
1333                    variant
1334                )
1335            )
1336        inherit(conf, cp, bsp_map, arch, bsp, [])
1337    return bsp_map
1338
1339
1340def check_compiler(ctx, compiler):
1341    if compiler not in compilers:
1342        ctx.fatal(
1343            "Specified compiler '{}' is not one of {}".format(
1344                compiler, compilers
1345            )
1346        )
1347
1348
1349def get_compiler(conf, cp, variant):
1350    try:
1351        value = cp.get(variant, "COMPILER")
1352        cp.remove_option(variant, "COMPILER")
1353        value = no_unicode(value)
1354        check_compiler(conf, value)
1355    except configparser.NoOptionError:
1356        value = "gcc"
1357    return value
1358
1359
1360def configure_variant(conf, cp, bsp_map, path_list, top_group, variant):
1361    conf.msg("Configure board support package (BSP)", variant, color="YELLOW")
1362
1363    conf.setenv(variant)
1364    arch, bsp_name = variant.split("/")
1365    bsp_base = bsp_map.get(bsp_name, bsp_name)
1366    arch_bsp = arch + "/" + bsp_base
1367
1368    conf.env["ARCH"] = arch
1369    conf.env["ARCH_BSP"] = arch_bsp
1370    conf.env["BSP_BASE"] = bsp_base
1371    conf.env["BSP_NAME"] = bsp_name
1372    conf.env["DEST_OS"] = "rtems"
1373
1374    # For the enabled-by evaluation we have to use the base BSP defined by the
1375    # build specification and not the BSP name provided by the user.
1376    conf.env["ENABLE"] = [get_compiler(conf, cp, variant), arch, arch_bsp]
1377
1378    conf.env["TOP"] = conf.path.abspath()
1379    conf.env["TOPGROUP"] = top_group
1380    conf.env["VARIANT"] = variant
1381
1382    cic = ConfigItemContext(cp, path_list)
1383
1384    items[conf.env.TOPGROUP].configure(conf, cic)
1385
1386    try:
1387        bsp_item = bsps[arch][bsp_base]
1388    except KeyError:
1389        conf.fatal("No such base BSP: '{}'".format(variant))
1390    bsp_item.configure(conf, cic)
1391
1392    options = set([o[0].upper() for o in cp.items(variant)])
1393    for o in options.difference(cic.options):
1394        conf.msg("Unknown configuration option", o.upper(), color="RED")
1395
1396
1397def check_forbidden_options(ctx, opts):
1398    for o in opts:
1399        if getattr(ctx.options, "rtems_" + o):
1400            ctx.fatal(
1401                "The --rtems-{} command line option is not allowed in the {} command".format(
1402                    o.replace("_", "-"), ctx.cmd
1403                )
1404            )
1405
1406
1407def get_path_list(conf):
1408    path_list = []
1409    tools = conf.options.rtems_tools
1410    if tools is not None:
1411        for t in tools.split(","):
1412            path_list.extend([t + "/bin", t])
1413    path_list.append(conf.env.PREFIX + "/bin")
1414    path_list.extend(os.environ.get("PATH", "").split(os.pathsep))
1415    return path_list
1416
1417
1418def get_top_group(ctx):
1419    top_group = ctx.options.rtems_top_group
1420    if top_group is None:
1421        top_group = "/grp"
1422    if top_group not in items:
1423        ctx.fatal(
1424            "There is no top-level group with UID '{}' in the specification".format(
1425                top_group
1426            )
1427        )
1428    return top_group
1429
1430
1431def configure(conf):
1432    check_forbidden_options(conf, ["compiler"])
1433    check_environment(conf)
1434    conf.env["SPECS"] = load_items_from_options(conf)
1435    top_group = get_top_group(conf)
1436    cp = load_config_files(conf)
1437    bsp_map = resolve_option_inheritance(conf, cp)
1438    path_list = get_path_list(conf)
1439    variant_list = []
1440    for variant in cp.sections():
1441        variant = no_unicode(variant)
1442        variant_list.append(variant)
1443        configure_variant(conf, cp, bsp_map, path_list, top_group, variant)
1444    conf.setenv("")
1445    conf.env["VARIANTS"] = variant_list
1446
1447
1448def append_variant_builds(bld):
1449    import waflib.Options
1450    from waflib.Build import (
1451        BuildContext,
1452        CleanContext,
1453        InstallContext,
1454        UninstallContext,
1455    )
1456
1457    for var in bld.env["VARIANTS"]:
1458        for c in (BuildContext, CleanContext, InstallContext, UninstallContext):
1459            name = c.__name__.replace("Context", "").lower()
1460
1461            class magic(c):
1462                cmd = name + "_" + var
1463                variant = var
1464
1465        waflib.Options.commands.append(bld.cmd + "_" + var)
1466
1467
1468def long_command_line_workaround(bld):
1469    if is_windows_host:
1470        bld.load("long_gcc")
1471
1472
1473def build(bld):
1474    if not bld.variant:
1475        check_forbidden_options(
1476            bld, ["compiler", "config", "specs", "tools", "top_group"]
1477        )
1478        load_items(bld, bld.env.SPECS)
1479        append_variant_builds(bld)
1480        return
1481    long_command_line_workaround(bld)
1482    bic = BuildItemContext(bld.env.ARCH_INCLUDES.split(), [], [], [])
1483    bsps[bld.env.ARCH][bld.env.BSP_BASE].build(bld, bic)
1484    items[bld.env.TOPGROUP].build(bld, bic)
1485
1486
1487def add_log_filter(name):
1488    msg = "'" + name + "' finished successfully"
1489
1490    class Filter:
1491        def filter(self, rec):
1492            return not msg in rec.getMessage()
1493
1494    import logging
1495
1496    logging.getLogger("waflib").addFilter(Filter())
1497
1498
1499def get_white_list(ctx):
1500    white_list = ctx.options.rtems_bsps
1501    if white_list:
1502        white_list = white_list.split(",")
1503    return white_list
1504
1505
1506def is_in_white_list(variant, white_list):
1507    if not white_list:
1508        return True
1509    for pattern in white_list:
1510        if re.match(pattern + "$", variant):
1511            return True
1512    return False
1513
1514
1515def no_matches_error(ctx, white_list):
1516    if white_list:
1517        ctx.fatal(
1518            "No BSP matches with the specified patterns: '{}'".format(
1519                "', '".join(white_list)
1520            )
1521        )
1522    else:
1523        ctx.fatal("The build specification contains no BSPs")
1524
1525
1526def bsp_defaults(ctx):
1527    """get all options with default values for base BSP variants"""
1528    check_forbidden_options(ctx, ["config", "tools"])
1529    add_log_filter(ctx.cmd)
1530    load_items_from_options(ctx)
1531    top_group = get_top_group(ctx)
1532    white_list = get_white_list(ctx)
1533    compiler = ctx.options.rtems_compiler
1534    if compiler is not None:
1535        check_compiler(ctx, compiler)
1536    else:
1537        compiler = "gcc"
1538    first = True
1539    for arch in sorted(bsps):
1540        for bsp in sorted(bsps[arch]):
1541            variant = arch + "/" + bsp
1542            if is_in_white_list(variant, white_list):
1543                if not first:
1544                    print("")
1545                first = False
1546                print(
1547                    """[{}]
1548# Selects the compiler used to build the BSP (allowed values are "gcc" and
1549# "clang").  Please note that the values of some options depend on the compiler
1550# selection and changing the compiler may lead to unpredictable behaviour if
1551# these options are not adjusted as well.  Use the --rtems-compiler command line
1552# option to get the default values for a particular compiler via
1553# ./waf bsp_defaults.
1554COMPILER = {}""".format(
1555                        variant, compiler
1556                    )
1557                )
1558                enable = [compiler, arch, variant]
1559                items[top_group].defaults(enable, variant)
1560                bsps[arch][bsp].defaults(enable, variant)
1561    if first:
1562        no_matches_error(ctx, white_list)
1563
1564
1565def bsp_list(ctx):
1566    """lists base BSP variants"""
1567    check_forbidden_options(ctx, ["compiler", "config", "tools", "top_group"])
1568    add_log_filter(ctx.cmd)
1569    load_items_from_options(ctx)
1570    white_list = get_white_list(ctx)
1571    first = True
1572    for arch in sorted(bsps):
1573        for bsp in sorted(bsps[arch]):
1574            variant = arch + "/" + bsp
1575            if is_in_white_list(variant, white_list):
1576                first = False
1577                print(variant)
1578    if first:
1579        no_matches_error(ctx, white_list)
Note: See TracBrowser for help on using the repository browser.