source: rtems-libbsd/waf_libbsd.py @ 1588cf1

5-freebsd-12
Last change on this file since 1588cf1 was 1588cf1, checked in by Christian Mauderer <christian.mauderer@…>, on May 2, 2018 at 12:59:48 PM

waf: Fix source code generators.

There have been some bugs with the strings left from the transition to
directly building from libbsd.py.

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