source: rtems-libbsd/waf_libbsd.py @ 8a7d33c

Last change on this file since 8a7d33c was 8a7d33c, checked in by Chris Johns <chrisj@…>, on Apr 4, 2019 at 6:16:28 AM

Fix the sed generator for processing INI configuration files.

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