source: rtems-libbsd/waf_libbsd.py @ 93f1904

5-freebsd-12
Last change on this file since 93f1904 was 93f1904, checked in by Christian Mauderer <christian.mauderer@…>, on Apr 25, 2018 at 12:51:07 PM

waf: Generate a rtems/bsd/modules.h

The generated file defines a RTEMS_BSD_MODULE_xxx for each enabled
module. That is usefull for conditional compilation depending on whether
a module is build not.

Update #3351.

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