source: rtems-libbsd/waf_libbsd.py @ 9d65f34

Last change on this file since 9d65f34 was 9d65f34, checked in by Kinsey Moore <kinsey.moore@…>, on 10/07/21 at 20:26:35

waf_libbsd: Fix typo in previous patch

There was a typo in the patch that added the HAVE_<LIBRARY> definition
that prevented "./waf configure" from succeeding. This adds the missing
character.

  • Property mode set to 100644
File size: 23.4 KB
Line 
1# SPDX-License-Identifier: BSD-2-Clause
2"""LibBSD build configuration to waf integration module.
3"""
4
5# Copyright (c) 2015, 2020 Chris Johns <chrisj@rtems.org>. All rights reserved.
6#
7# Copyright (c) 2009, 2015 embedded brains GmbH.  All rights reserved.
8#
9#   embedded brains GmbH
10#   Dornierstr. 4
11#   82178 Puchheim
12#   Germany
13#   <info@embedded-brains.de>
14#
15# Copyright (c) 2012 OAR Corporation. All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions
19# are met:
20# 1. Redistributions of source code must retain the above copyright
21#    notice, this list of conditions and the following disclaimer.
22# 2. Redistributions in binary form must reproduce the above copyright
23#    notice, this list of conditions and the following disclaimer in the
24#    documentation and/or other materials provided with the distribution.
25#
26# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36# POSSIBILITY OF SUCH DAMAGE.
37
38from __future__ import print_function
39
40import os
41import sys
42import tempfile
43import re
44
45import builder
46
47import rtems_waf.rtems as rtems
48
49
50BUILDSET_DIR = builder.BUILDSET_DIR
51BUILDSET_DEFAULT = builder.BUILDSET_DEFAULT
52
53windows = os.name == 'nt'
54
55if windows:
56    host_shell = 'sh -c '
57else:
58    host_shell = ''
59
60def _add_flags_if_not_present(current_flags, addional_flags):
61    for flag in addional_flags:
62        if flag not in current_flags:
63            current_flags.append(flag)
64
65#
66# The waf builder for libbsd.
67#
68class Builder(builder.ModuleManager):
69    def __init__(self, trace=False):
70        super(Builder, self).__init__()
71        self.trace = trace
72        self.data = {}
73
74    @staticmethod
75    def _sourceList(bld, files):
76        sources = []
77        if type(files) is dict:
78            for cfg in files:
79                if cfg in ['cflags', 'includes']:
80                    continue
81                if cfg != 'default':
82                    for c in cfg.split(' '):
83                        if not bld.env['HAVE_%s' % (c)]:
84                            continue
85                sources += sorted(files[cfg])
86        else:
87            sources = sorted(files)
88        return sources
89
90    def generate(self, rtems_version):
91        def _dataInsert(data, cpu, space, frag):
92            #
93            # The default handler returns None. Skip it.
94            #
95            if frag is not None:
96                # Start at the top of the tree
97                d = data
98                path = frag[0]
99                if path[0] not in d:
100                    d[path[0]] = {}
101                # Select the sub-part of the tree as the compile options
102                # specialise how files are built.
103                d = d[path[0]]
104                # Group based on the space, ie kernel or user
105                if space not in d:
106                    d[space] = {}
107                d = d[space]
108                if type(path[1]) is list:
109                    p = ' '.join(path[1])
110                else:
111                    p = path[1]
112                if p not in d:
113                    d[p] = {}
114                d = d[p]
115                if cpu not in d:
116                    d[cpu] = {}
117                config = frag[0][2][0]
118                if config != 'default':
119                    if 'configure' not in data:
120                        data['configure'] = {}
121                    configTest = frag[1]['configTest']
122                    if configTest not in data['configure']:
123                        data['configure'][configTest] = {}
124                    data['configure'][configTest][config] = frag[0][2][1]
125                if type(frag[1]) is list:
126                    if config not in d[cpu]:
127                        d[cpu][config] = []
128                    d[cpu][config] += frag[1]
129                else:
130                    d[cpu][config] = frag[1]
131                #
132                # The CPU is for files and the flags and includes are common.
133                #
134                if len(frag) > 3:
135                    if 'cflags' not in d:
136                        d['cflags'] = []
137                    d['cflags'] += frag[2]
138                    d['cflags'] = list(set(d['cflags']))
139                if len(frag) >= 3 and None not in frag[-1]:
140                    if 'includes' not in d:
141                        d['includes'] = []
142                    d['includes'] += frag[-1]
143                    d['includes'] = list(set(d['includes']))
144
145        self.generateBuild()
146
147        self.data = {}
148
149        enabled_modules = self.getEnabledModules()
150        for mn in enabled_modules:
151            m = self[mn]
152            enabled = True
153            for dep in m.dependencies:
154                if dep not in enabled_modules:
155                    enabled = False
156                    break
157            if enabled:
158                for f in m.files:
159                    _dataInsert(self.data, 'all', f.getSpace(),
160                                f.getFragment())
161                for cpu, files in sorted(m.cpuDependentSourceFiles.items()):
162                    for f in files:
163                        _dataInsert(self.data, cpu, f.getSpace(),
164                                    f.getFragment())
165
166        # Start here if you need to understand self.data. Add 'True or'
167        if self.trace:
168            import pprint
169            pprint.pprint(self.data)
170
171    def bsp_configure(self, conf, arch_bsp):
172        if 'configure' in self.data:
173            for configTest in self.data['configure']:
174                for cfg in self.data['configure'][configTest]:
175                    if configTest == 'header':
176                        for h in self.data['configure'][configTest][cfg]:
177                            conf.check(header_name=h,
178                                       features="c",
179                                       includes=conf.env.IFLAGS,
180                                       mandatory=False)
181                    elif configTest == 'library':
182                        for l in self.data['configure'][configTest][cfg]:
183                            if conf.check_cc(lib=l,
184                                             fragment=rtems.test_application(),
185                                             execute=False,
186                                             mandatory=False):
187                                conf.env['HAVE_%s' % l.upper()] = True
188                    else:
189                        bld.fatal('invalid config test: %s' % (configTest))
190            section_flags = ["-fdata-sections", "-ffunction-sections"]
191            _add_flags_if_not_present(conf.env.CFLAGS, section_flags)
192            _add_flags_if_not_present(conf.env.CXXFLAGS, section_flags)
193            _add_flags_if_not_present(conf.env.LINKFLAGS, ["-Wl,--gc-sections"])
194
195    def build(self, bld):
196        #
197        # Localize the config.
198        #
199        config = self.getConfiguration()
200        module_header_path = "rtems/bsd"
201        module_header_name = "modules.h"
202
203        #
204        #
205        # C/C++ flags
206        #
207        common_flags = []
208        common_flags += ['-O%s' % (bld.env.OPTIMIZATION)]
209        if 'common-flags' in config:
210            common_flags += [f for f in config['common-flags']]
211        if bld.env.WARNINGS and 'common-warnings' in config:
212            common_flags += [f for f in config['common-warnings']]
213        elif 'common-no-warnings' in config:
214            common_flags += [f for f in config['common-no-warnings']]
215        if 'cflags' in config:
216            cflags = config['cflags'] + common_flags
217        if 'cxxflags' in config:
218            cxxflags = config['cxxflags'] + common_flags
219
220        #
221        # Defines
222        #
223        defines = []
224        if len(bld.env.FREEBSD_OPTIONS) > 0:
225            for o in bld.env.FREEBSD_OPTIONS.split(','):
226                defines += ['%s=1' % (o.strip().upper())]
227
228        #
229        # Include paths, maintain paths for each build space.
230        #
231        include_paths = config['include-paths']
232        if 'build' not in include_paths:
233            bld.fatal('no build include path found in include-path defaults')
234        buildinclude = include_paths['build']
235        if isinstance(buildinclude, list):
236            buildinclude = buildinclude[0]
237        inc_paths = sorted(include_paths)
238        inc_paths.remove('build')
239        inc_paths.remove('cpu')
240        includes = {}
241        for inc in inc_paths:
242            includes[inc] = include_paths[inc]
243        # cpu include paths must be the first searched
244        if 'cpu' in include_paths:
245            cpu = bld.get_env()['RTEMS_ARCH']
246            for i in include_paths['cpu']:
247                includes['kernel'].insert(0, i.replace('@CPU@', cpu))
248        includes['kernel'] += [buildinclude]
249
250        #
251        # Path mappings
252        #
253        if 'path-mappings' in config:
254            for source, target in config['path-mappings']:
255                for space in includes:
256                    incs = includes[space]
257                    if source in incs:
258                        target = [target] if isinstance(target,
259                                                        str) else target
260                        i = incs.index(source)
261                        incs.remove(source)
262                        incs[i:i] = target
263
264        #
265        # Place the kernel include paths after the user paths
266        #
267        includes['user'] += includes['kernel']
268
269        #
270        # Collect the libbsd uses
271        #
272        libbsd_use = []
273
274        #
275        # Network test configuration
276        #
277        if not os.path.exists(bld.env.NET_CONFIG):
278            bld.fatal('network configuraiton \'%s\' not found' %
279                      (bld.env.NET_CONFIG))
280        tags = [
281            'NET_CFG_INTERFACE_0', 'NET_CFG_SELF_IP', 'NET_CFG_NETMASK',
282            'NET_CFG_PEER_IP', 'NET_CFG_GATEWAY_IP'
283        ]
284        try:
285            net_cfg_lines = open(bld.env.NET_CONFIG).readlines()
286        except:
287            bld.fatal('network configuraiton \'%s\' read failed' %
288                      (bld.env.NET_CONFIG))
289        lc = 0
290        sed = 'sed '
291        for l in net_cfg_lines:
292            lc += 1
293            if l.strip().startswith('NET_CFG_'):
294                ls = l.split('=')
295                if len(ls) != 2:
296                    bld.fatal('network configuraiton \'%s\' ' + \
297                              'parse error: %d: %s' % (bld.env.NET_CONFIG, lc, l))
298                lhs = ls[0].strip()
299                rhs = ls[1].strip()
300                for t in tags:
301                    if lhs == t:
302                        sed += "-e 's/@%s@/%s/' " % (t, rhs)
303        bld(target="testsuite/include/rtems/bsd/test/network-config.h",
304            source="testsuite/include/rtems/bsd/test/network-config.h.in",
305            rule=sed + " < ${SRC} > ${TGT}",
306            update_outputs=True)
307
308        #
309        # Add a copy rule for all headers where the install path and the source
310        # path are not the same.
311        #
312        if 'header-paths' in config:
313            header_build_copy_paths = [
314                hp for hp in config['header-paths']
315                if hp[2] != '' and not hp[0].endswith(hp[2])
316            ]
317            for headers in header_build_copy_paths:
318                target = os.path.join(buildinclude, headers[2])
319                start_dir = bld.path.find_dir(headers[0])
320                for header in start_dir.ant_glob(headers[1]):
321                    relsourcepath = header.path_from(start_dir)
322                    targetheader = os.path.join(target, relsourcepath)
323                    bld(features='subst',
324                        target=targetheader,
325                        source=header,
326                        is_copy=True)
327
328        #
329        # Generate a header that contains information about enabled modules
330        #
331        def rtems_libbsd_modules_h_gen(self):
332            output = ""
333            output += '/*\n'
334            output += ' * This file contains a list of modules that have been\n'
335            output += ' * enabled during libbsd build. It is a generated file\n'
336            output += ' * DO NOT EDIT MANUALLY.\n'
337            output += ' */'
338            output += '\n'
339            output += '#ifndef RTEMS_BSD_MODULES_H\n'
340            for mod in config['modules-enabled']:
341                modname = re.sub("[^A-Za-z0-9]", "_", mod.upper())
342                output += '#define RTEMS_BSD_MODULE_{} 1\n'.format(modname)
343            output += '#endif /* RTEMS_BSD_MODULES_H */\n'
344            self.outputs[0].write(output)
345
346        modules_h_file_with_path = os.path.join(buildinclude,
347                                                module_header_path,
348                                                module_header_name)
349        bld(rule=rtems_libbsd_modules_h_gen,
350            target=modules_h_file_with_path,
351            before=['c', 'cxx'])
352
353        #
354        # Add the specific rule based builders
355        #
356
357        #
358        # KVM Symbols
359        #
360        if 'KVMSymbols' in self.data:
361            kvmsymbols = self.data['KVMSymbols']['kernel']
362            if 'includes' in kvmsymbols['files']:
363                kvmsymbols_includes = kvmsymbols['files']['includes']
364            else:
365                kvmsymbols_includes = []
366            bld(target=kvmsymbols['files']['all']['default'][0],
367                source='rtemsbsd/rtems/generate_kvm_symbols',
368                rule=host_shell + './${SRC} > ${TGT}',
369                update_outputs=True)
370            bld.objects(target='kvmsymbols',
371                        features='c',
372                        cflags=cflags,
373                        includes=kvmsymbols_includes + includes['kernel'],
374                        source=kvmsymbols['files']['all']['default'][0])
375            libbsd_use += ["kvmsymbols"]
376
377        bld.add_group()
378
379        #
380        # RPC Generation
381        #
382        if 'RPCGen' in self.data:
383            if bld.env.AUTO_REGEN:
384                rpcgen = self.data['RPCGen']['user']
385                rpcname = rpcgen['files']['all']['default'][0][:-2]
386                bld(target=rpcname + '.h',
387                    source=rpcname + '.x',
388                    rule=host_shell + '${RPCGEN} -h -o ${TGT} ${SRC}')
389
390        #
391        # Route keywords
392        #
393        if 'RouteKeywords' in self.data:
394            if bld.env.AUTO_REGEN:
395                routekw = self.data['RouteKeywords']['user']
396                rkwname = routekw['files']['all']['default'][0]
397                rkw_rule = host_shell + "cat ${SRC} | " + \
398                           "awk 'BEGIN { r = 0 } { if (NF == 1) " + \
399                           "printf \"#define\\tK_%%s\\t%%d\\n\\t{\\\"%%s\\\", K_%%s},\\n\", " + \
400                           "toupper($1), ++r, $1, toupper($1)}' > ${TGT}"
401                bld(target=rkwname + '.h', source=rkwname, rule=rkw_rule)
402
403        #
404        # Lex
405        #
406        if 'lex' in self.data:
407            lexes = self.data['lex']['user']
408            for l in sorted(lexes.keys()):
409                lex = lexes[l]['all']['default']
410                if 'cflags' in lex:
411                    lexDefines = [d[2:] for d in lex['cflags']]
412                else:
413                    lexDefines = []
414                if 'includes' in lex:
415                    lexIncludes = lex['includes']
416                else:
417                    lexIncludes = []
418                lex_rule = host_shell + '${LEX} -P ' + lex['sym'] + ' -t ${SRC} | ' + \
419                           'sed -e \'/YY_BUF_SIZE/s/16384/1024/\' > ${TGT}'
420                if bld.env.AUTO_REGEN:
421                    bld(target=lex['file'][:-2] + '.c',
422                        source=lex['file'],
423                        rule=lex_rule)
424                if lex['build']:
425                    bld.objects(target='lex_%s' % (lex['sym']),
426                                features='c',
427                                cflags=cflags,
428                                includes=lexIncludes + includes['user'],
429                                defines=defines + lexDefines,
430                                source=lex['file'][:-2] + '.c')
431                libbsd_use += ['lex_%s' % (lex['sym'])]
432
433        #
434        # Yacc
435        #
436        if 'yacc' in self.data:
437            yaccs = self.data['yacc']['user']
438            for y in sorted(yaccs.keys()):
439                yacc = yaccs[y]['all']['default']
440                yaccFile = yacc['file']
441                if yacc['sym'] is not None:
442                    yaccSym = yacc['sym']
443                else:
444                    yaccSym = os.path.basename(yaccFile)[:-2]
445                yaccHeader = '%s/%s' % (os.path.dirname(yaccFile),
446                                        yacc['header'])
447                if 'cflags' in yacc:
448                    yaccDefines = [d[2:] for d in yacc['cflags']]
449                else:
450                    yaccDefines = []
451                if 'includes' in yacc:
452                    yaccIncludes = yacc['includes']
453                else:
454                    yaccIncludes = []
455                yacc_rule = host_shell + '${YACC} -b ' + yaccSym + \
456                            ' -d -p ' + yaccSym + ' ${SRC} && ' + \
457                            'sed -e \'/YY_BUF_SIZE/s/16384/1024/\' < ' + \
458                            yaccSym + '.tab.c > ${TGT} && ' + \
459                            'rm -f ' + yaccSym + '.tab.c && mv ' + yaccSym + '.tab.h ' + yaccHeader
460                if bld.env.AUTO_REGEN:
461                    bld(target=yaccFile[:-2] + '.c',
462                        source=yaccFile,
463                        rule=yacc_rule)
464                if yacc['build']:
465                    bld.objects(target='yacc_%s' % (yaccSym),
466                                features='c',
467                                cflags=cflags,
468                                includes=yaccIncludes + includes['user'],
469                                defines=defines + yaccDefines,
470                                source=yaccFile[:-2] + '.c')
471                libbsd_use += ['yacc_%s' % (yaccSym)]
472
473        #
474        # We have 'm' different sets of flags and there can be 'n' cpus
475        # specific files for those flags.
476        #
477        objs = 0
478        for space in sorted(self.data['sources']):
479            sources = sorted(self.data['sources'][space])
480            if space == 'kernel' and 'default' in sources:
481                sources.remove('default')
482            for flags in sources:
483                objs += 1
484                build = self.data['sources'][space][flags]
485                target = 'objs%02d' % (objs)
486                bld_sources = Builder._sourceList(bld, build['all'])
487                archs = sorted(build)
488                for i in ['all', 'cflags', 'includes']:
489                    if i in archs:
490                        archs.remove(i)
491                for arch in archs:
492                    if bld.get_env()['RTEMS_ARCH'] == arch:
493                        bld_sources += Builder._sourceList(bld, build[arch])
494                bld_cflags = sorted(build.get('cflags', []))
495                if 'default' in bld_cflags:
496                    bld_cflags.remove('default')
497                bld.objects(target=target,
498                            features='c cxx',
499                            cflags=cflags + bld_cflags,
500                            cxxflags=cxxflags,
501                            includes=sorted(build.get('includes', [])) +
502                            includes[space],
503                            defines=defines,
504                            source=bld_sources)
505                libbsd_use += [target]
506
507        #
508        # We hold the kernel 'default' cflags set of files to the end to
509        # create the static library with.
510        #
511        build = self.data['sources']['kernel']['default']
512        bld_sources = Builder._sourceList(bld, build['all'])
513        archs = sorted(build)
514        archs.remove('all')
515        for arch in archs:
516            if bld.get_env()['RTEMS_ARCH'] == arch:
517                bld_sources += Builder._sourceList(bld, build[arch])
518        bld.stlib(target='bsd',
519                  features='c cxx',
520                  cflags=cflags,
521                  cxxflags=cxxflags,
522                  includes=includes['kernel'],
523                  defines=defines,
524                  source=bld_sources,
525                  use=libbsd_use)
526
527        #
528        # Installs.
529        #
530        # Header file collector.
531        #
532        arch_lib_path = rtems.arch_bsp_lib_path(bld.env.RTEMS_VERSION,
533                                                bld.env.RTEMS_ARCH_BSP)
534        arch_inc_path = rtems.arch_bsp_include_path(bld.env.RTEMS_VERSION,
535                                                    bld.env.RTEMS_ARCH_BSP)
536
537        bld.install_files("${PREFIX}/" + arch_lib_path, ["libbsd.a"])
538
539        if 'header-paths' in config:
540            headerPaths = config['header-paths']
541            cpu = bld.get_env()['RTEMS_ARCH']
542            for headers in headerPaths:
543                paths = [headers[0].replace('@CPU@', cpu)]
544                # Apply the path mappings
545                for source, targets in config['path-mappings']:
546                    if source in paths:
547                        i = paths.index(source)
548                        paths.remove(source)
549                        paths[i:i] = targets
550
551                for hp in paths:
552                    # Get the dest path
553                    ipath = os.path.join(arch_inc_path, headers[2])
554                    start_dir = bld.path.find_dir(hp)
555                    if start_dir != None:
556                        bld.install_files("${PREFIX}/" + ipath,
557                                        start_dir.ant_glob(headers[1]),
558                                        cwd=start_dir,
559                                        relative_trick=True)
560
561        bld.install_files(os.path.join("${PREFIX}", arch_inc_path,
562                                       module_header_path),
563                          modules_h_file_with_path,
564                          cwd=bld.path)
565
566        #
567        # Tests
568        #
569        tests = []
570        if 'tests' in self.data:
571            tests = self.data['tests']['user']
572        enabled_modules = self.getEnabledModules()
573        for testName in sorted(tests):
574            test = tests[testName]['all']
575            test_source = []
576            libs = ['bsd', 'm', 'z', 'rtemstest']
577            for cfg in test:
578                build_test = True
579                for mod in test[cfg]['modules']:
580                    if mod not in enabled_modules:
581                        build_test = False
582                        break
583                if build_test and cfg != 'default':
584                    for c in cfg.split(' '):
585                        if not bld.env['HAVE_%s' % (c)]:
586                            build_test = False
587                            break
588                if build_test:
589                    test_sources = ['testsuite/%s/%s.c' % (testName, f) \
590                                    for f in test[cfg]['files']]
591                    libs = test[cfg]['libs'] + libs
592            if build_test:
593                bld.program(target='%s.exe' % (testName),
594                            features='cprogram',
595                            cflags=cflags,
596                            includes=includes['user'],
597                            source=test_sources,
598                            use=['bsd'],
599                            lib=libs,
600                            install_path=None)
Note: See TracBrowser for help on using the repository browser.