source: rtems_waf/rtems.py @ f490cd3

Last change on this file since f490cd3 was f490cd3, checked in by Christian Mauderer <christian.mauderer@…>, on 04/06/18 at 12:07:51

Fix bsp_init hook.

  • Property mode set to 100644
File size: 29.7 KB
RevLine 
[0c2d2a3]1
[8220ad1]2# Copyright 2012-2016 Chris Johns (chrisj@rtems.org)
[993d33b]3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6
7# 1. Redistributions of source code must retain the above copyright notice, this
8# list of conditions and the following disclaimer.
9
10# 2. Redistributions in binary form must reproduce the above copyright notice,
11# this list of conditions and the following disclaimer in the documentation
12# and/or other materials provided with the distribution.
13
14# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
[0c2d2a3]25from __future__ import print_function
26
[993d33b]27#
28# RTEMS support for applications.
29#
30
31import copy
32import os
33import os.path
[b548c77]34from . import pkgconfig
[993d33b]35import re
36import subprocess
[254b827]37import sys
[993d33b]38
[8220ad1]39rtems_default_version = None
[993d33b]40rtems_filters = None
[1aef190]41rtems_long_commands = False
[993d33b]42
[254b827]43windows = os.name == 'nt' or sys.platform in ['msys', 'cygwin']
[eb6ff97]44
[993d33b]45def options(opt):
46    opt.add_option('--rtems',
[080dbb5]47                   default = None,
[993d33b]48                   dest = 'rtems_path',
[a0b06b0]49                   help = 'Path to an installed RTEMS (defaults to prefix).')
[993d33b]50    opt.add_option('--rtems-tools',
51                   default = None,
52                   dest = 'rtems_tools',
[080dbb5]53                   help = 'Path to RTEMS tools (defaults to path to installed RTEMS).')
[993d33b]54    opt.add_option('--rtems-version',
[a0b06b0]55                   default = None,
[993d33b]56                   dest = 'rtems_version',
[a0b06b0]57                   help = 'RTEMS version (default is derived from prefix).')
[993d33b]58    opt.add_option('--rtems-archs',
59                   default = 'all',
60                   dest = 'rtems_archs',
61                   help = 'List of RTEMS architectures to build.')
62    opt.add_option('--rtems-bsps',
63                   default = 'all',
64                   dest = 'rtems_bsps',
65                   help = 'List of BSPs to build.')
66    opt.add_option('--show-commands',
67                   action = 'store_true',
68                   default = False,
69                   dest = 'show_commands',
70                   help = 'Print the commands as strings.')
71
[4ef2f41]72def init(ctx, filters = None, version = None, long_commands = False, bsp_init = None):
[993d33b]73    global rtems_filters
[8220ad1]74    global rtems_default_version
[1aef190]75    global rtems_long_commands
[8220ad1]76
77    #
78    # Set the RTEMS filter to the context.
79    #
80    rtems_filters = filters
81
82    #
83    # Set the default version, can be overridden.
84    #
85    rtems_default_version = version
[993d33b]86
[1aef190]87    #
88    # Set the long commands option.
89    #
90    rtems_long_commands = long_commands
91
[f490cd3]92    env = None
93    contexts = []
[993d33b]94    try:
95        import waflib.Options
96        import waflib.ConfigSet
97
98        #
99        # Load the configuation set from the lock file.
100        #
101        env = waflib.ConfigSet.ConfigSet()
102        env.load(waflib.Options.lockfile)
103
104        #
105        # Check the tools, architectures and bsps.
106        #
[a0b06b0]107        rtems_version, rtems_path, rtems_bin, rtems_tools, archs, arch_bsps = \
108            check_options(ctx,
109                          env.options['prefix'],
110                          env.options['rtems_tools'],
111                          env.options['rtems_path'],
112                          env.options['rtems_version'],
113                          env.options['rtems_archs'],
114                          env.options['rtems_bsps'])
[993d33b]115
116        #
[4ef2f41]117        # Update the contexts for all the bsps.
[993d33b]118        #
119        from waflib.Build import BuildContext, CleanContext, \
120            InstallContext, UninstallContext
121        for x in arch_bsps:
122            for y in (BuildContext, CleanContext, InstallContext, UninstallContext):
123                name = y.__name__.replace('Context','').lower()
124                class context(y):
125                    cmd = name + '-' + x
126                    variant = x
[4ef2f41]127                contexts += [context]
[993d33b]128
129        #
[32555ff]130        # Transform the command to per BSP commands.
[993d33b]131        #
[32555ff]132        commands = []
133        for cmd in waflib.Options.commands:
134            if cmd in ['build', 'clean', 'install']:
[993d33b]135                for x in arch_bsps:
[32555ff]136                    commands += [cmd + '-' + x]
[93e5545]137            else:
138                commands += [cmd]
[32555ff]139        waflib.Options.commands = commands
[993d33b]140    except:
141        pass
142
[4ef2f41]143    if bsp_init:
144        bsp_init(ctx, env, contexts)
145
[ddb5f2d]146def configure(conf, bsp_configure = None):
[8220ad1]147    #
148    # Check the environment for any flags.
149    #
150    for f in ['CC', 'CXX', 'AS', 'LD', 'AR', 'LINK_CC', 'LINK_CXX',
151              'CPPFLAGS', 'CFLAGS', 'CXXFLAGS', 'ASFLAGS', 'LINKFLAGS', 'LIB'
152              'WFLAGS', 'RFLAGS', 'MFLAGS', 'IFLAGS']:
153        if f in os.environ:
154            conf.msg('Environment variable set', f, color = 'RED')
155
[993d33b]156    #
[1aef190]157    # Handle the configurable commands options.
[993d33b]158    #
159    if conf.options.show_commands:
160        show_commands = 'yes'
161    else:
162        show_commands = 'no'
[eb6ff97]163    if rtems_long_commands and windows:
[1aef190]164        long_commands = 'yes'
165    else:
166        long_commands = 'no'
[993d33b]167
[a0b06b0]168    rtems_version, rtems_path, rtems_bin, rtems_tools, archs, arch_bsps = \
169        check_options(conf,
170                      conf.options.prefix,
171                      conf.options.rtems_tools,
172                      conf.options.rtems_path,
173                      conf.options.rtems_version,
174                      conf.options.rtems_archs,
175                      conf.options.rtems_bsps)
[993d33b]176
177    if rtems_tools is None:
178        conf.fatal('RTEMS tools not found.')
179
180    _log_header(conf)
181
[8220ad1]182    conf.msg('RTEMS Version', rtems_version, 'YELLOW')
[993d33b]183    conf.msg('Architectures', ', '.join(archs), 'YELLOW')
184
185    tools = {}
186    env = conf.env.derive()
187
188    for ab in arch_bsps:
189        conf.setenv(ab, env)
190
191        conf.msg('Board Support Package', ab, 'YELLOW')
192
[1aef190]193        #
194        # Show and long commands support.
195        #
196        conf.env.SHOW_COMMANDS = show_commands
197        conf.env.LONG_COMMANDS = long_commands
198
199        conf.msg('Show commands', show_commands)
200        conf.msg('Long commands', long_commands)
201
[993d33b]202        arch = _arch_from_arch_bsp(ab)
[28fddb2]203        bsp  = _bsp_from_arch_bsp(ab)
204
205        conf.env.ARCH_BSP = '%s/%s' % (arch.split('-')[0], bsp)
[993d33b]206
[080dbb5]207        conf.env.RTEMS_PATH = rtems_path
[a0b06b0]208        conf.env.RTEMS_VERSION = rtems_version
[993d33b]209        conf.env.RTEMS_ARCH_BSP = ab
210        conf.env.RTEMS_ARCH = arch.split('-')[0]
211        conf.env.RTEMS_ARCH_RTEMS = arch
[28fddb2]212        conf.env.RTEMS_BSP = bsp
[993d33b]213
[080dbb5]214        tools = _find_tools(conf, arch, [rtems_bin] + rtems_tools, tools)
[993d33b]215        for t in tools[arch]:
216            conf.env[t] = tools[arch][t]
217
218        conf.load('gcc')
219        conf.load('g++')
220        conf.load('gas')
221
[8220ad1]222        #
223        # Get the version of the tools being used.
224        #
225        rtems_cc = conf.env.CC[0]
226        try:
227            import waflib.Context
228            out = conf.cmd_and_log([rtems_cc, '--version'],
229                                   output = waflib.Context.STDOUT)
230        except Exception as e:
231            conf.fatal('CC version not found: %s' % (e.stderr))
232        #
233        # First line is the version
234        #
235        vline = out.split('\n')[0]
236        conf.msg('Compiler version (%s)' % (os.path.basename(rtems_cc)),
237                                            ' '.join(vline.split()[2:]))
238
[080dbb5]239        flags = _load_flags(conf, ab, rtems_path)
[993d33b]240
241        cflags = _filter_flags('cflags', flags['CFLAGS'],
[080dbb5]242                               arch, rtems_path)
[993d33b]243        ldflags = _filter_flags('ldflags', flags['LDFLAGS'],
[080dbb5]244                               arch, rtems_path)
[993d33b]245
246        conf.env.CFLAGS    = cflags['cflags']
[0c2d2a3]247        conf.env.CXXFLAGS  = cflags['cflags']
[993d33b]248        conf.env.ASFLAGS   = cflags['cflags']
249        conf.env.WFLAGS    = cflags['warnings']
250        conf.env.RFLAGS    = cflags['specs']
251        conf.env.MFLAGS    = cflags['machines']
252        conf.env.IFLAGS    = cflags['includes']
253        conf.env.LINKFLAGS = cflags['cflags'] + ldflags['ldflags']
254        conf.env.LIB       = flags['LIB']
[b0afac0]255        conf.env.LIBPATH   = ldflags['libpath']
[993d33b]256
[7bcf72b]257        conf.env.RTRACE_WRAPPER_ST = '-W %s'
258
[993d33b]259        #
260        # Checks for various RTEMS features.
261        #
[b2ce230]262        conf.multicheck({ 'header_name': 'rtems/score/cpuopts.h'},
263                        msg = 'Checking for RTEMS CPU options header',
[993d33b]264                        mandatory = True)
[080dbb5]265        load_cpuopts(conf, ab, rtems_path)
[b2ce230]266        conf.multicheck({ 'header_name': 'rtems.h'},
267                        msg = 'Checking for RTEMS header',
268                        mandatory = True)
[993d33b]269
270        #
271        # Add tweaks.
272        #
273        tweaks(conf, ab)
274
275        #
[28fddb2]276        # If the user has supplied a BSP specific configure function
277        # call it.
[993d33b]278        #
[28fddb2]279        if bsp_configure:
280            bsp_configure(conf, ab)
[993d33b]281
282        conf.setenv('', env)
283
284    conf.env.RTEMS_TOOLS = rtems_tools
285    conf.env.ARCHS = archs
286    conf.env.ARCH_BSPS = arch_bsps
287
288    conf.env.SHOW_COMMANDS = show_commands
[1aef190]289    conf.env.LONG_COMMANDS = long_commands
[993d33b]290
291def build(bld):
292    if bld.env.SHOW_COMMANDS == 'yes':
293        output_command_line()
[1aef190]294    if bld.env.LONG_COMMANDS == 'yes':
295        long_command_line()
[993d33b]296
297def load_cpuopts(conf, arch_bsp, rtems_path):
298    options = ['RTEMS_DEBUG',
299               'RTEMS_MULTIPROCESSING',
300               'RTEMS_NEWLIB',
301               'RTEMS_POSIX_API',
302               'RTEMS_SMP',
[4a549d2]303               'RTEMS_NETWORKING']
[993d33b]304    for opt in options:
305        enabled = check_opt(conf, opt, 'rtems/score/cpuopts.h', arch_bsp, rtems_path)
306        if enabled:
307            conf.env[opt] = 'Yes'
308        else:
309            conf.env[opt] = 'No'
310
311def check_opt(conf, opt, header, arch_bsp, rtems_path):
312    code  = '#include <%s>%s' % (header, os.linesep)
313    code += '#ifndef %s%s' % (opt, os.linesep)
314    code += ' #error %s is not defined%s' % (opt, os.linesep)
315    code += '#endif%s' % (os.linesep)
316    code += '#if %s%s' % (opt, os.linesep)
317    code += ' /* %s is true */%s' % (opt, os.linesep)
318    code += '#else%s' % (os.linesep)
319    code += ' #error %s is false%s' % (opt, os.linesep)
320    code += '#endif%s' % (os.linesep)
321    code += 'int main() { return 0; }%s' % (os.linesep)
322    try:
323        conf.check_cc(fragment = code,
324                      execute = False,
325                      define_ret = False,
326                      msg = 'Checking for %s' % (opt))
327    except conf.errors.WafError:
328        return False;
329    return True
330
331def tweaks(conf, arch_bsp):
332    #
333    # Hack to work around NIOS2 naming.
334    #
335    if conf.env.RTEMS_ARCH in ['nios2']:
336        conf.env.OBJCOPY_FLAGS = ['-O', 'elf32-littlenios2']
337    elif conf.env.RTEMS_ARCH in ['arm']:
338        conf.env.OBJCOPY_FLAGS = ['-I', 'binary', '-O', 'elf32-littlearm']
339    else:
340        conf.env.OBJCOPY_FLAGS = ['-O', 'elf32-' + conf.env.RTEMS_ARCH]
341
342    #
343    # Check for a i386 PC bsp.
344    #
345    if re.match('i386-.*-pc[3456]86', arch_bsp) is not None:
346        conf.env.LINKFLAGS += ['-Wl,-Ttext,0x00100000']
347
348    if '-ffunction-sections' in conf.env.CFLAGS:
349      conf.env.LINKFLAGS += ['-Wl,--gc-sections']
350
[a0b06b0]351def check_options(ctx, prefix, rtems_tools, rtems_path, rtems_version, rtems_archs, rtems_bsps):
[080dbb5]352    #
353    # Set defaults
354    #
[a0b06b0]355    if rtems_version is None:
[8220ad1]356        if rtems_default_version is None:
357            m = re.compile('[^0-9.]*([0-9.]+)$').match(prefix)
358            if m:
359                rtems_version = m.group(1)
360            else:
361                ctx.fatal('RTEMS version cannot derived from prefix: ' + prefix)
[a0b06b0]362        else:
[8220ad1]363            rtems_version = rtems_default_version
[080dbb5]364    if rtems_path is None:
[a0b06b0]365        rtems_path = prefix
[080dbb5]366    if rtems_tools is None:
367        rtems_tools = rtems_path
368
[993d33b]369    #
370    # Check the paths are valid.
371    #
372    if not os.path.exists(rtems_path):
373        ctx.fatal('RTEMS path not found.')
374    if os.path.exists(os.path.join(rtems_path, 'lib', 'pkgconfig')):
375        rtems_config = None
376    elif os.path.exists(os.path.join(rtems_path, 'rtems-config')):
377        rtems_config = os.path.join(rtems_path, 'rtems-config')
378    else:
379        ctx.fatal('RTEMS path is not valid. No lib/pkgconfig or rtems-config found.')
380    if os.path.exists(os.path.join(rtems_path, 'bin')):
381        rtems_bin = os.path.join(rtems_path, 'bin')
382    else:
383        ctx.fatal('RTEMS path is not valid. No bin directory found.')
384
385    #
386    # We can more than one path to tools. This happens when testing different
387    # versions.
388    #
[080dbb5]389    rt = rtems_tools.split(',')
390    tools = []
391    for path in rt:
392        if not os.path.exists(path):
393            ctx.fatal('RTEMS tools path not found: ' + path)
394        if not os.path.exists(os.path.join(path, 'bin')):
395            ctx.fatal('RTEMS tools path does not contain a \'bin\' directory: ' + path)
396        tools += [os.path.join(path, 'bin')]
[993d33b]397
398    #
399    # Filter the tools.
400    #
401    tools = filter(ctx, 'tools', tools)
402
403    #
404    # Match the archs requested against the ones found. If the user
405    # wants all (default) set all used.
406    #
407    if rtems_archs == 'all':
408        archs = _find_installed_archs(rtems_config, rtems_path, rtems_version)
409    else:
410        archs = _check_archs(rtems_config, rtems_archs, rtems_path, rtems_version)
411
412    #
413    # Filter the architectures.
414    #
415    archs = filter(ctx, 'archs', archs)
416
417    #
418    # We some.
419    #
420    if len(archs) == 0:
421        ctx.fatal('Could not find any architectures')
422
423    #
424    # Get the list of valid BSPs. This process filters the architectures
425    # to those referenced by the BSPs.
426    #
427    if rtems_bsps == 'all':
428        arch_bsps = _find_installed_arch_bsps(rtems_config, rtems_path, archs, rtems_version)
429    else:
430        arch_bsps = _check_arch_bsps(rtems_bsps, rtems_config, rtems_path, archs, rtems_version)
431
432    if len(arch_bsps) == 0:
433        ctx.fatal('No valid arch/bsps found')
434
435    #
436    # Filter the bsps.
437    #
438    arch_bsps = filter(ctx, 'bsps', arch_bsps)
439
[a0b06b0]440    return rtems_version, rtems_path, rtems_bin, tools, archs, arch_bsps
[993d33b]441
[28fddb2]442def check_env(ctx, var):
443    if var in ctx.env and len(ctx.env[var]) != 0:
444        return True
445    return False
446
[993d33b]447def check(ctx, option):
448    if option in ctx.env:
449        return ctx.env[option] == 'Yes'
450    return False
451
452def check_debug(ctx):
453    return check(ctx, 'RTEMS_DEBUG')
454
455def check_multiprocessing(ctx):
456    return check(ctx, 'RTEMS_MULTIPROCESSING')
457
458def check_newlib(ctx):
459    return check(ctx, 'RTEMS_NEWLIB')
460
461def check_posix(ctx):
462    return check(ctx, 'RTEMS_POSIX_API')
463
464def check_smp(ctx):
465    return check(ctx, 'RTEMS_SMP')
466
467def check_networking(ctx):
468    return check(ctx, 'RTEMS_NETWORKING')
469
470def arch(arch_bsp):
471    """ Given an arch/bsp return the architecture."""
472    return _arch_from_arch_bsp(arch_bsp).split('-')[0]
473
474def bsp(arch_bsp):
475    """ Given an arch/bsp return the BSP."""
476    return _bsp_from_arch_bsp(arch_bsp)
477
478def arch_bsps(ctx):
479    """ Return the list of arch/bsps we are building."""
480    return ctx.env.ARCH_BSPS
481
482def arch_bsp_env(ctx, arch_bsp):
483    return ctx.env_of_name(arch_bsp).derive()
484
485def filter(ctx, filter, items):
486    if rtems_filters is None:
487        return items
488    if type(rtems_filters) is not dict:
489        ctx.fatal("Invalid RTEMS filter type, " \
490                  "ie { 'tools': { 'in': [], 'out': [] }, 'arch': {}, 'bsps': {} }")
491    if filter not in rtems_filters:
492        return items
493    items_in = []
494    items_out = []
495    if 'in' in rtems_filters[filter]:
496        items_in = copy.copy(rtems_filters[filter]['in'])
497    if 'out' in rtems_filters[filter]:
498        items_out = copy.copy(rtems_filters[filter]['out'])
499    filtered_items = []
500    for i in items:
501        item = i
502        ab = '%s/%s' % (arch(item), bsp(item))
503        for inre in items_in:
504            if re.compile(inre).match(ab):
505                items_in.remove(inre)
506                filtered_items += [item]
507                item = None
508                break
509        if item is not None:
510            for outre in items_out:
511                if re.compile(outre).match(ab):
512                    item = None
513                    break
514        if item is not None:
515            filtered_items += [item]
516    if len(items_in) != 0:
517        ctx.fatal('Following %s not found: %s' % (filter, ', '.join(items_in)))
518    return sorted(filtered_items)
519
[080dbb5]520def arch_rtems_version(version, arch):
[993d33b]521    """ Return the RTEMS architecture path, ie sparc-rtems4.11."""
[080dbb5]522    return '%s-rtems%s' % (arch, version)
[993d33b]523
[080dbb5]524def arch_bsp_path(version, arch_bsp):
[993d33b]525    """ Return the BSP path."""
[080dbb5]526    return '%s/%s' % (arch_rtems_version(version, arch(arch_bsp)), bsp(arch_bsp))
[993d33b]527
[080dbb5]528def arch_bsp_include_path(version, arch_bsp):
[993d33b]529    """ Return the BSP include path."""
[080dbb5]530    return '%s/lib/include' % (arch_bsp_path(version, arch_bsp))
[993d33b]531
[080dbb5]532def arch_bsp_lib_path(version, arch_bsp):
[993d33b]533    """ Return the BSP library path. """
[080dbb5]534    return '%s/lib' % (arch_bsp_path(version, arch_bsp))
[993d33b]535
536def library_path(library, cc, cflags):
537    cmd = cc + cflags + ['-print-file-name=%s' % library]
538    a = subprocess.check_output(cmd)
539    lib = os.path.abspath(a.strip())
540    if os.path.exists(lib):
541        return os.path.dirname(lib)
542    return None
543
[b0afac0]544def root_filesystem(bld, name, files, tar, obj):
[8fcd500]545    tar_rule = 'tar -cf ${TGT} --format=ustar -C ../.. $(echo "${SRC}" | sed -e \'s/\.\.\/\.\.\///g\')'
[eb6ff97]546    if windows:
547        tar_rule = 'sh -c "%s"' % (tar_rule)
[b0afac0]548    bld(name = name + '_tar',
549        target = tar,
550        source = files,
[eb6ff97]551        rule = tar_rule)
[b0afac0]552    bld.objects(name = name,
553                target = obj,
554                source = tar,
555                rule = '${OBJCOPY} -I binary -B ${RTEMS_ARCH} ${OBJCOPY_FLAGS} ${SRC} ${TGT}')
556
[993d33b]557def clone_tasks(bld):
558    if bld.cmd == 'build':
559        for obj in bld.all_task_gen[:]:
560            for x in arch_bsp:
561                cloned_obj = obj.clone(x)
562                kind = Options.options.build_kind
563                if kind.find(x) < 0:
564                    cloned_obj.posted = True
565            obj.posted = True
566
567#
568# From the demos. Use this to get the command to cut+paste to play.
569#
570def output_command_line():
571    # first, display strings, people like them
572    from waflib import Utils, Logs
573    from waflib.Context import Context
574    def exec_command(self, cmd, **kw):
575        subprocess = Utils.subprocess
576        kw['shell'] = isinstance(cmd, str)
577        if isinstance(cmd, str):
578            Logs.info('%s' % cmd)
579        else:
[d793097]580            cmdstr = ' '.join(cmd)
581            Logs.info('(%d) %s' % (len(cmdstr), cmdstr)) # here is the change
[993d33b]582        Logs.debug('runner_env: kw=%s' % kw)
583        try:
584            if self.logger:
585                self.logger.info(cmd)
586                kw['stdout'] = kw['stderr'] = subprocess.PIPE
587                p = subprocess.Popen(cmd, **kw)
588                (out, err) = p.communicate()
589                if out:
590                    self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))
591                if err:
592                    self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))
593                return p.returncode
594            else:
595                p = subprocess.Popen(cmd, **kw)
596                return p.wait()
597        except OSError:
598            return -1
599    Context.exec_command = exec_command
600
601    # Change the outputs for tasks too
602    from waflib.Task import Task
603    def display(self):
604        return '' # no output on empty strings
605
606    Task.__str__ = display
607
[1aef190]608#
609# From the extras. Use this to support long command lines.
610#
611def long_command_line():
612    def exec_command(self, cmd, **kw):
613        # workaround for command line length limit:
614        # http://support.microsoft.com/kb/830473
615        import tempfile
616        tmp = None
617        try:
618            if not isinstance(cmd, str) and len(str(cmd)) > 8192:
619                (fd, tmp) = tempfile.mkstemp(dir=self.generator.bld.bldnode.abspath())
620                flat = ['"%s"' % x.replace('\\', '\\\\').replace('"', '\\"') for x in cmd[1:]]
621                try:
622                    os.write(fd, ' '.join(flat).encode())
623                finally:
624                    if tmp:
625                        os.close(fd)
626                # Line may be very long:
627                # Logs.debug('runner:' + ' '.join(flat))
[c161c8d]628                cmd = [cmd[0], '@' + tmp]
[1aef190]629            ret = super(self.__class__, self).exec_command(cmd, **kw)
630        finally:
631            if tmp:
632                os.remove(tmp)
633        return ret
634    for k in 'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():
635        cls = Task.classes.get(k)
636        if cls:
637            derived_class = type(k, (cls,), {})
638            derived_class.exec_command = exec_command
639            if hasattr(cls, 'hcode'):
640                derived_class.hcode = cls.hcode
641
[993d33b]642def _find_tools(conf, arch, paths, tools):
643    if arch not in tools:
644        arch_tools = {}
645        arch_tools['CC']          = conf.find_program([arch + '-gcc'], path_list = paths)
646        arch_tools['CXX']         = conf.find_program([arch + '-g++'], path_list = paths)
647        arch_tools['LINK_CC']     = arch_tools['CC']
648        arch_tools['LINK_CXX']    = arch_tools['CXX']
[8220ad1]649        arch_tools['AS']          = conf.find_program([arch + '-gcc'], path_list = paths)
650        arch_tools['LD']          = conf.find_program([arch + '-ld'],  path_list = paths)
[993d33b]651        arch_tools['AR']          = conf.find_program([arch + '-ar'], path_list = paths)
652        arch_tools['NM']          = conf.find_program([arch + '-nm'], path_list = paths)
653        arch_tools['OBJDUMP']     = conf.find_program([arch + '-objdump'], path_list = paths)
654        arch_tools['OBJCOPY']     = conf.find_program([arch + '-objcopy'], path_list = paths)
655        arch_tools['READELF']     = conf.find_program([arch + '-readelf'], path_list = paths)
656        arch_tools['STRIP']       = conf.find_program([arch + '-strip'], path_list = paths)
657        arch_tools['RTEMS_LD']    = conf.find_program(['rtems-ld'], path_list = paths,
658                                                      mandatory = False)
[28fddb2]659        arch_tools['RTEMS_TLD']   = conf.find_program(['rtems-tld'], path_list = paths,
660                                                      mandatory = False)
[993d33b]661        arch_tools['RTEMS_BIN2C'] = conf.find_program(['rtems-bin2c'], path_list = paths,
662                                                      mandatory = False)
663        arch_tools['TAR']         = conf.find_program(['tar'], mandatory = False)
664        tools[arch] = arch_tools
665    return tools
666
667def _find_installed_archs(config, path, version):
668    archs = []
669    if config is None:
670        for d in os.listdir(path):
671            if d.endswith('-rtems' + version):
672                archs += [d]
673    else:
674        a = subprocess.check_output([config, '--list-format', '"%(arch)s"'])
675        a = a[:-1].replace('"', '')
676        archs = set(a.split())
[9343280]677        archs = ['%s-rtems%s' % (x, version) for x in archs]
[993d33b]678    archs.sort()
679    return archs
680
681def _check_archs(config, req, path, version):
682    installed = _find_installed_archs(config, path, version)
683    archs = []
684    for a in req.split(','):
685        arch = a + '-rtems' + version
686        if arch in installed:
687            archs += [arch]
688    archs.sort()
689    return archs
690
691def _find_installed_arch_bsps(config, path, archs, version):
692    arch_bsps = []
693    if config is None:
694        for f in os.listdir(_pkgconfig_path(path)):
695            if f.endswith('.pc'):
696                if _arch_from_arch_bsp(f[:-3]) in archs:
697                    arch_bsps += [f[:-3]]
698    else:
699        ab = subprocess.check_output([config, '--list-format'])
700        ab = ab[:-1].replace('"', '')
701        ab = ab.replace('/', '-rtems%s-' % (version))
702        arch_bsps = [x for x in set(ab.split())]
703    arch_bsps.sort()
704    return arch_bsps
705
706def _check_arch_bsps(req, config, path, archs, version):
707    archs_bsps = []
708    for ab in req.split(','):
709        abl = ab.split('/')
710        if len(abl) != 2:
711            return []
712        found = False
713        for arch in archs:
714            a = '%s-rtems%s' % (abl[0], version)
715            if a == arch:
716                found = True
717                break
718        if not found:
719            return []
720        archs_bsps += ['%s-%s' % (a, abl[1])]
721    if len(archs_bsps) == 0:
722        return []
723    installed = _find_installed_arch_bsps(config, path, archs, version)
724    bsps = []
725    for b in archs_bsps:
726        if b in installed:
727            bsps += [b]
728    bsps.sort()
729    return bsps
730
731def _arch_from_arch_bsp(arch_bsp):
732    return '-'.join(arch_bsp.split('-')[:2])
733
734def _bsp_from_arch_bsp(arch_bsp):
735    return '-'.join(arch_bsp.split('-')[2:])
736
737def _pkgconfig_path(path):
738    return os.path.join(path, 'lib', 'pkgconfig')
739
740def _load_flags(conf, arch_bsp, path):
741    if not os.path.exists(path):
742        ctx.fatal('RTEMS path not found.')
743    if os.path.exists(_pkgconfig_path(path)):
744        pc = os.path.join(_pkgconfig_path(path), arch_bsp + '.pc')
745        conf.to_log('Opening and load pkgconfig: ' + pc)
746        pkg = pkgconfig.package(pc)
747        config = None
748    elif os.path.exists(os.path.join(path, 'rtems-config')):
749        config = os.path.join(path, 'rtems-config')
750        pkg = None
751    flags = {}
752    _log_header(conf)
753    flags['CFLAGS'] = _load_flags_set('CFLAGS', arch_bsp, conf, config, pkg)
754    flags['LDFLAGS'] = _load_flags_set('LDFLAGS', arch_bsp, conf, config, pkg)
755    flags['LIB'] = _load_flags_set('LIB', arch_bsp, conf, config, pkg)
756    return flags
757
758def _load_flags_set(flags, arch_bsp, conf, config, pkg):
759    conf.to_log('%s ->' % flags)
760    if pkg is not None:
761        flagstr = ''
762        try:
763            flagstr = pkg.get(flags)
764        except pkgconfig.error as e:
765            conf.to_log('pkconfig warning: ' + e.msg)
766        conf.to_log('  ' + flagstr)
767    else:
768        flags_map = { 'CFLAGS': '--cflags',
769                      'LDFLAGS': '--ldflags',
770                      'LIB': '--libs' }
771        ab = arch_bsp.split('-')
772        #conf.check_cfg(path = config,
773        #               package = '',
774        #               uselib_store = 'rtems',
775        #               args = '--bsp %s/%s %s' % (ab[0], ab[2], flags_map[flags]))
776        #print conf.env
777        #print '%r' % conf
778        #flagstr = '-l -c'
779        flagstr = subprocess.check_output([config, '--bsp', '%s/%s' % (ab[0], ab[2]), flags_map[flags]])
780        #print flags, ">>>>", flagstr
781        if flags == 'CFLAGS':
782            flagstr += ' -DWAF_BUILD=1'
783        if flags == 'LIB':
784            flagstr = 'rtemscpu rtemsbsp c rtemscpu rtemsbsp'
785    return flagstr.split()
786
787def _filter_flags(label, flags, arch, rtems_path):
788
789    flag_groups = \
790        [ { 'key': 'warnings', 'path': False, 'flags': { '-W': 1 }, 'cflags': False, 'lflags': False },
791          { 'key': 'includes', 'path': True,  'flags': { '-I': 1, '-isystem': 2, '-sysroot': 2 } },
[b0afac0]792          { 'key': 'libpath',  'path': True,  'flags': { '-L': 1 } },
[993d33b]793          { 'key': 'machines', 'path': True,  'flags': { '-O': 1, '-m': 1, '-f': 1 } },
794          { 'key': 'specs',    'path': True,  'flags': { '-q': 1, '-B': 2, '--specs': 2 } } ]
795
796    flags = _strip_cflags(flags)
797
798    _flags = { label: [] }
799    for fg in flag_groups:
800        _flags[fg['key']] = []
801
802    iflags = iter(flags)
803    for opt in iflags:
804        in_label = True
805        opts = []
806        for fg in flag_groups:
807            key = fg['key']
808            for flag in fg['flags']:
809                if opt.startswith(flag):
810                    opt_count = fg['flags'][flag]
811                    if opt_count > 1:
812                        if opt != flag:
813                            opt_count -= 1
814                            if fg['path'] and arch in opt:
815                                opt = '%s%s/%s' % (flag, rtems_path,
816                                                   opt[opt.find(arch):])
817                    opts += [opt]
818                    for c in range(1, opt_count):
819                        opt = next(iflags)
820                        if fg['path'] and arch in opt:
821                            opt = '%s%s/%s' % (f, rtems_path,
822                                               opt[opt.find(arch):])
823                        opts += [opt]
824                    _flags[key] += opts
825                    if label in fg and not fg[label]:
826                        in_label = False
827                    break
828            if in_label:
829                _flags[label] += opts
830    return _flags
831
832def _strip_cflags(cflags):
833    _cflags = []
834    for o in cflags:
835        if o.startswith('-O'):
836            pass
837        elif o.startswith('-g'):
838            pass
839        else:
840            _cflags += [o]
841    return _cflags
842
843def _log_header(conf):
844    conf.to_log('-----------------------------------------')
845
846from waflib import Task
847from waflib import TaskGen
848from waflib import Utils
849from waflib import Node
850from waflib.Tools.ccroot import link_task, USELIB_VARS
[28fddb2]851
[993d33b]852USELIB_VARS['rap'] = set(['RTEMS_LINKFLAGS'])
[db8c6f0]853USELIB_VARS['rtrace'] = set(['RTRACE_FLAGS', 'RTRACE_CFG', 'RTRACE_WRAPPER', 'RTRACE_LINKCMDS'])
854
[993d33b]855class rap(link_task):
856    "Link object files into a RTEMS application"
857    run_str = '${RTEMS_LD} ${RTEMS_LINKFLAGS} --cc ${CC} ${SRC} -o ${TGT[0].abspath()} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'
858    ext_out = ['.rap']
859    vars    = ['RTEMS_LINKFLAGS', 'LINKDEPS']
860    inst_to = '${BINDIR}'
[28fddb2]861
862class rtrace(link_task):
863    "Link object files into a RTEMS trace application"
[7bcf72b]864    run_str = '${RTEMS_TLD} ${RTACE_FLAGS} ${RTRACE_WRAPPER_ST:RTRACE_WRAPPER} -C ${RTRACE_CFG} -r ${RTEMS_PATH} -B ${ARCH_BSP} -c ${CC} -l ${CC} -- ${SRC} ${LINKFLAGS} ${RTRACE_LINKFLAGS} -o ${TGT[0].abspath()} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'
[28fddb2]865    ext_out = ['.texe']
[db8c6f0]866    vars    = ['RTRACE_FLAGS', 'RTRACE_CFG', 'RTRACE_WRAPER', 'RTRACE_LINKFLAGS', 'LINKDEPS']
[28fddb2]867    inst_to = '${BINDIR}'
[db8c6f0]868    color = 'PINK'
Note: See TracBrowser for help on using the repository browser.