source: rtems-libbsd/waf_libbsd.py @ a1e3251

55-freebsd-126-freebsd-12
Last change on this file since a1e3251 was 01855a5, checked in by Christian Mauderer <christian.mauderer@…>, on 05/07/18 at 08:19:28

waf: Allow to only generate lex and yacc.

In some applications, it's usefull if the files generated by lex or yacc
are not build automatically. With that it is for example possible to
create a wrapper source file that sets some defines before the generated
code is parsed.

  • Property mode set to 100644
File size: 19.9 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        for l in net_cfg_lines:
231            lc += 1
232            if l.strip().startswith('NET_CFG_'):
233                ls = l.split('=')
234                if len(ls) != 2:
235                    bld.fatal('network configuraiton \'%s\' ' + \
236                              'parse error: %d: %s' % (bld.env.NET_CONFIG, lc, l))
237                lhs = ls[0].strip()
238                rhs = ls[1].strip()
239                sed = 'sed '
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 = self.data['tests']
503        for testName in sorted(tests):
504            test = self.data['tests'][testName]['all']
505            test_source = []
506            libs = ['bsd', 'm', 'z']
507            for cfg in test:
508                build_test = True
509                if cfg != 'default':
510                    for c in cfg.split(' '):
511                        if not bld.env['HAVE_%s' % (c)]:
512                            build_test = False
513                            break
514                if build_test:
515                    test_sources = ['testsuite/%s/%s.c' % (testName, f) \
516                                    for f in test[cfg]['files']]
517                    libs = test[cfg]['libs'] + libs
518            if build_test:
519                bld.program(target = '%s.exe' % (testName),
520                            features = 'cprogram',
521                            cflags = cflags,
522                            includes = includes,
523                            source = test_sources,
524                            use = ['bsd'],
525                            lib = libs,
526                            install_path = None)
Note: See TracBrowser for help on using the repository browser.