source: rtems/wscript @ edea93c

Last change on this file since edea93c was f20078a, checked in by Sebastian Huber <sebastian.huber@…>, on 09/12/22 at 08:35:21

build: Use enabled by for defaults

Merge the "default" and "default-by-variant" attributes. Use an
"enabled-by" expression to select the default value based on the enabled
set. This makes it possible to select default values depending on other
options. For example you could choose memory settings based on whether
RTEMS_SMP is enabled or disabled.

The change was tested by comparing the output of

./waf bspdefaults

before and after the change.

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