예제 #1
0
def _dump_one_runner_info(cache, args, build_dir, indent):
    runner = args.runner
    cls = get_runner_cls(runner)

    if cache is None:
        _dump_runner_opt_help(runner, cls)
        _dump_runner_caps(cls, '')
        return

    available = runner in cache.get_list('ZEPHYR_RUNNERS')
    cfg = cached_runner_config(build_dir, cache)

    log.inf('Build directory:', colorize=True)
    log.inf(INDENT + build_dir)
    log.inf('Board:', colorize=True)
    log.inf(INDENT + cache['CACHED_BOARD'])
    log.inf('CMake cache:', colorize=True)
    log.inf(INDENT + cache.cache_file)
    log.inf(runner,
            'is available:',
            'yes' if available else 'no',
            colorize=True)
    _dump_runner_opt_help(runner, cls)
    _dump_runner_config(cfg, '', indent)
    if available:
        _dump_runner_cached_opts(cache, runner, '', indent)
    _dump_runner_caps(cls, '')
    if not available:
        log.wrn('Runner', runner, 'is not configured in this build.')
예제 #2
0
    def sign(self, command, build_dir, bcfg, formats):
        if not formats:
            return

        args = command.args
        b = pathlib.Path(build_dir)
        cache = CMakeCache.from_build_dir(build_dir)

        tool_path = self.find_imgtool(command, args)
        # The vector table offset is set in Kconfig:
        vtoff = self.get_cfg(command, bcfg, 'CONFIG_TEXT_SECTION_OFFSET')
        # Flash device write alignment and the partition's slot size
        # come from devicetree:
        flash = self.edt_flash_node(b, cache)
        align, addr, size = self.edt_flash_params(flash)

        runner_config = cached_runner_config(build_dir, cache)
        if 'bin' in formats:
            in_bin = runner_config.bin_file
            if not in_bin:
                log.die("can't find unsigned .bin to sign")
        else:
            in_bin = None
        if 'hex' in formats:
            in_hex = runner_config.hex_file
            if not in_hex:
                log.die("can't find unsigned .hex to sign")
        else:
            in_hex = None

        log.banner('image configuration:')
        log.inf('partition offset: {0} (0x{0:x})'.format(addr))
        log.inf('partition size: {0} (0x{0:x})'.format(size))
        log.inf('text section offset: {0} (0x{0:x})'.format(vtoff))

        # Base sign command.
        #
        # We provide a default --version in case the user is just
        # messing around and doesn't want to set one. It will be
        # overridden if there is a --version in args.tool_args.
        sign_base = [tool_path, 'sign',
                     '--version', '0.0.0+0',
                     '--align', str(align),
                     '--header-size', str(vtoff),
                     '--slot-size', str(size)]
        sign_base.extend(args.tool_args)

        log.banner('signed binaries:')
        if in_bin:
            out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin')
            sign_bin = sign_base + [in_bin, out_bin]
            log.inf('bin: {}'.format(out_bin))
            log.dbg(quote_sh_list(sign_bin))
            subprocess.check_call(sign_bin)
        if in_hex:
            out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex')
            sign_hex = sign_base + [in_hex, out_hex]
            log.inf('hex: {}'.format(out_hex))
            log.dbg(quote_sh_list(sign_hex))
            subprocess.check_call(sign_hex)
예제 #3
0
파일: sign.py 프로젝트: wingunder/zephyr
    def sign(self, args):
        cache = cmake.CMakeCache.from_build_dir(args.build_dir)
        runner_config = cached_runner_config(args.build_dir, cache)
        bcfg = BuildConfiguration(args.build_dir)

        # Build a signed .bin
        if args.gen_bin and runner_config.bin_file:
            sign_bin = self.sign_cmd(args, bcfg, runner_config.bin_file,
                                     args.sbin)
            log.dbg(quote_sh_list(sign_bin))
            subprocess.check_call(sign_bin)

        # Build a signed .hex
        if args.gen_hex and runner_config.hex_file:
            sign_hex = self.sign_cmd(args, bcfg, runner_config.hex_file,
                                     args.shex)
            log.dbg(quote_sh_list(sign_hex))
            subprocess.check_call(sign_hex)
예제 #4
0
    def sign(self, command, build_dir, bcfg, formats):
        args = command.args

        if args.tool_path:
            command.check_force(
                shutil.which(args.tool_path),
                '--tool-path {}: not an executable'.format(args.tool_path))
            tool_path = args.tool_path
        else:
            tool_path = shutil.which('imgtool')
            if not tool_path:
                log.die(
                    'imgtool not found; either install it',
                    '(e.g. "pip3 install imgtool") or provide --tool-path')

        align, vtoff, slot_size = [
            self.get_cfg(command, bcfg, x)
            for x in ('DT_FLASH_WRITE_BLOCK_SIZE',
                      'CONFIG_TEXT_SECTION_OFFSET',
                      'DT_FLASH_AREA_IMAGE_0_SIZE')
        ]

        log.dbg('build config: --align={}, --header-size={}, --slot-size={}'.
                format(align, vtoff, slot_size))

        # Base sign command.
        #
        # We provide a default --version in case the user is just
        # messing around and doesn't want to set one. It will be
        # overridden if there is a --version in args.tool_args.
        sign_base = [tool_path, 'sign', '--version', '0.0.0+0']
        if align:
            sign_base.extend(['--align', str(align)])
        else:
            log.wrn('expected nonzero flash alignment, but '
                    'DT_FLASH_WRITE_BLOCK_SIZE={} '
                    "in build directory's ({}) device tree".format(
                        align, build_dir))

        if vtoff:
            sign_base.extend(['--header-size', str(vtoff)])
        else:
            log.wrn('expected nonzero header size, but '
                    'CONFIG_TEXT_SECTION_OFFSET={} '
                    "in build directory's ({}) .config".format(
                        vtoff, build_dir))

        if slot_size:
            sign_base.extend(['--slot-size', str(slot_size)])
        else:
            log.wrn('expected nonzero slot size, but '
                    'DT_FLASH_AREA_IMAGE_0_SIZE={} '
                    "in build directory's ({}) device tree".format(
                        slot_size, build_dir))

        b = pathlib.Path(build_dir)
        cache = cmake.CMakeCache.from_build_dir(build_dir)
        runner_config = cached_runner_config(build_dir, cache)

        # Build a signed .bin
        if 'bin' in formats and runner_config.bin_file:
            out_bin = args.sbin or str(b / 'zephyr' / 'zephyr.signed.bin')
            log.inf('Generating:', out_bin)
            sign_bin = (sign_base + args.tool_args +
                        [runner_config.bin_file, out_bin])
            log.dbg(quote_sh_list(sign_bin))
            subprocess.check_call(sign_bin)

        # Build a signed .hex
        if 'hex' in formats and runner_config.hex_file:
            out_hex = args.shex or str(b / 'zephyr' / 'zephyr.signed.hex')
            log.inf('Generating:', out_hex)
            sign_hex = (sign_base + args.tool_args +
                        [runner_config.hex_file, out_hex])
            log.dbg(quote_sh_list(sign_hex))
            subprocess.check_call(sign_hex)
예제 #5
0
def _dump_context(command, args, runner_args, cached_runner_var):
    build_dir = _build_dir(args, die_if_none=False)

    # Try to figure out the CMake cache file based on the build
    # directory or an explicit argument.
    if build_dir is not None:
        cache_file = path.abspath(
            path.join(build_dir, args.cmake_cache or cmake.DEFAULT_CACHE))
    elif args.cmake_cache:
        cache_file = path.abspath(args.cmake_cache)
    else:
        cache_file = None

    # Load the cache itself, if possible.
    if cache_file is None:
        log.wrn('No build directory (--build-dir) or CMake cache '
                '(--cache-file) given or found; output will be limited')
        cache = None
    else:
        try:
            cache = cmake.CMakeCache(cache_file)
        except Exception:
            log.die('Cannot load cache {}.'.format(cache_file))

    # If we have a build directory, try to ensure build artifacts are
    # up to date. If that doesn't work, still try to print information
    # on a best-effort basis.
    if build_dir and not args.skip_rebuild:
        try:
            cmake.run_build(build_dir)
        except CalledProcessError:
            msg = 'Failed re-building application; cannot load context. '
            if args.build_dir:
                msg += 'Is {} the right --build-dir?'.format(args.build_dir)
            else:
                msg += textwrap.dedent('''\
                Use --build-dir (-d) to specify a build directory; the one
                used was {}.'''.format(build_dir))
            log.die('\n'.join(
                textwrap.wrap(msg,
                              initial_indent='',
                              subsequent_indent=INDENT,
                              break_on_hyphens=False)))

    if cache is None:
        _dump_no_context_info(command, args)
        if not args.runner:
            return

    if args.runner:
        # Just information on one runner was requested.
        _dump_one_runner_info(cache, args, build_dir, INDENT)
        return

    board = cache['CACHED_BOARD']

    all_cls = {
        cls.name(): cls
        for cls in ZephyrBinaryRunner.get_runners()
        if command.name in cls.capabilities().commands
    }
    available = [r for r in cache.get_list('ZEPHYR_RUNNERS') if r in all_cls]
    available_cls = {r: all_cls[r] for r in available if r in all_cls}

    default_runner = cache.get(cached_runner_var)
    cfg = cached_runner_config(build_dir, cache)

    log.inf('All Zephyr runners which support {}:'.format(command.name),
            colorize=True)
    for line in util.wrap(', '.join(all_cls.keys()), INDENT):
        log.inf(line)
    log.inf('(Not all may work with this build, see available runners below.)',
            colorize=True)

    if cache is None:
        log.warn('Missing or invalid CMake cache {}; there is no context.',
                 'Use --build-dir to specify the build directory.')
        return

    log.inf('Build directory:', colorize=True)
    log.inf(INDENT + build_dir)
    log.inf('Board:', colorize=True)
    log.inf(INDENT + board)
    log.inf('CMake cache:', colorize=True)
    log.inf(INDENT + cache_file)

    if not available:
        # Bail with a message if no runners are available.
        msg = ('No runners available for {}. '
               'Consult the documentation for instructions on how to run '
               'binaries on this target.').format(board)
        for line in util.wrap(msg, ''):
            log.inf(line, colorize=True)
        return

    log.inf('Available {} runners:'.format(command.name), colorize=True)
    log.inf(INDENT + ', '.join(available))
    log.inf('Additional options for available',
            command.name,
            'runners:',
            colorize=True)
    for runner in available:
        _dump_runner_opt_help(runner, all_cls[runner])
    log.inf('Default {} runner:'.format(command.name), colorize=True)
    log.inf(INDENT + default_runner)
    _dump_runner_config(cfg, '', INDENT)
    log.inf('Runner-specific information:', colorize=True)
    for runner in available:
        log.inf('{}{}:'.format(INDENT, runner), colorize=True)
        _dump_runner_cached_opts(cache, runner, INDENT * 2, INDENT * 3)
        _dump_runner_caps(available_cls[runner], INDENT * 2)

    if len(available) > 1:
        log.inf('(Add -r RUNNER to just print information about one runner.)',
                colorize=True)
예제 #6
0
def do_run_common(command, args, runner_args, cached_runner_var):
    if args.context:
        _dump_context(command, args, runner_args, cached_runner_var)
        return

    command_name = command.name
    build_dir = _build_dir(args)

    if not args.skip_rebuild:
        try:
            cmake.run_build(build_dir)
        except CalledProcessError:
            if args.build_dir:
                log.die('cannot run {}, build in {} failed'.format(
                    command_name, args.build_dir))
            else:
                log.die('cannot run {}; no --build-dir given and build in '
                        'current directory {} failed'.format(
                            command_name, build_dir))

    # Runner creation, phase 1.
    #
    # Get the default runner name from the cache, allowing a command
    # line override. Get the ZephyrBinaryRunner class by name, and
    # make sure it supports the command.

    cache_file = path.join(build_dir, args.cmake_cache or cmake.DEFAULT_CACHE)
    cache = cmake.CMakeCache(cache_file)
    board = cache['CACHED_BOARD']
    available = cache.get_list('ZEPHYR_RUNNERS')
    if not available:
        log.wrn('No cached runners are available in', cache_file)
    runner = args.runner or cache.get(cached_runner_var)

    if runner is None:
        raise CommandContextError(
            textwrap.dedent("""
        No {} runner available for {}. Please either specify one
        manually, or check your board's documentation for
        alternative instructions.""".format(command_name, board)))

    log.inf('Using runner:', runner)
    if runner not in available:
        log.wrn('Runner {} is not configured for use with {}, '
                'this may not work'.format(runner, board))
    runner_cls = get_runner_cls(runner)
    if command_name not in runner_cls.capabilities().commands:
        log.die('Runner {} does not support command {}'.format(
            runner, command_name))

    # Runner creation, phase 2.
    #
    # At this point, the common options above are already parsed in
    # 'args', and unrecognized arguments are in 'runner_args'.
    #
    # - Pull the RunnerConfig out of the cache
    # - Override cached values with applicable command-line options

    cfg = cached_runner_config(build_dir, cache)
    _override_config_from_namespace(cfg, args)

    # Runner creation, phase 3.
    #
    # - Pull out cached runner arguments, and append command-line
    #   values (which should override the cache)
    # - Construct a runner-specific argument parser to handle cached
    #   values plus overrides given in runner_args
    # - Parse arguments and create runner instance from final
    #   RunnerConfig and parsed arguments.

    cached_runner_args = cache.get_list('ZEPHYR_RUNNER_ARGS_{}'.format(
        cmake.make_c_identifier(runner)))
    assert isinstance(runner_args, list), runner_args
    # If the user passed -- to force the parent argument parser to stop
    # parsing, it will show up here, and needs to be filtered out.
    runner_args = [arg for arg in runner_args if arg != '--']
    final_runner_args = cached_runner_args + runner_args
    parser = argparse.ArgumentParser(prog=runner)
    runner_cls.add_parser(parser)
    parsed_args, unknown = parser.parse_known_args(args=final_runner_args)
    if unknown:
        raise CommandContextError('Runner', runner,
                                  'received unknown arguments', unknown)
    runner = runner_cls.create(cfg, parsed_args)
    runner.run(command_name)
예제 #7
0
def do_run_common(command, args, runner_args, cached_runner_var):
    if args.context:
        _dump_context(command, args, runner_args, cached_runner_var)
        return

    command_name = command.name
    build_dir = _build_dir(args)

    if not args.skip_rebuild:
        _banner('west {}: rebuilding'.format(command_name))
        try:
            cmake.run_build(build_dir)
        except CalledProcessError:
            if args.build_dir:
                log.die('cannot run {}, build in {} failed'.format(
                    command_name, args.build_dir))
            else:
                log.die('cannot run {}; no --build-dir given and build in '
                        'current directory {} failed'.format(
                            command_name, build_dir))

    # Runner creation, phase 1.
    #
    # Get the default runner name from the cache, allowing a command
    # line override. Get the ZephyrBinaryRunner class by name, and
    # make sure it supports the command.

    cache_file = path.join(build_dir, args.cmake_cache or cmake.DEFAULT_CACHE)
    try:
        cache = cmake.CMakeCache(cache_file)
    except FileNotFoundError:
        log.die('no CMake cache found (expected one at {})'.format(cache_file))
    board = cache['CACHED_BOARD']
    available = cache.get_list('ZEPHYR_RUNNERS')
    if not available:
        log.wrn('No cached runners are available in', cache_file)
    runner = args.runner or cache.get(cached_runner_var)

    if runner is None:
        log.die('No', command_name, 'runner available for board', board,
                '({} is not in the cache).'.format(cached_runner_var),
                "Check your board's documentation for instructions.")

    _banner('west {}: using runner {}'.format(command_name, runner))
    if runner not in available:
        log.wrn('Runner {} is not configured for use with {}, '
                'this may not work'.format(runner, board))
    runner_cls = get_runner_cls(runner)
    if command_name not in runner_cls.capabilities().commands:
        log.die('Runner {} does not support command {}'.format(
            runner, command_name))

    # Runner creation, phase 2.
    #
    # At this point, the common options above are already parsed in
    # 'args', and unrecognized arguments are in 'runner_args'.
    #
    # - Set up runner logging to delegate to west.
    # - Pull the RunnerConfig out of the cache
    # - Override cached values with applicable command-line options

    logger = logging.getLogger('runners')
    logger.setLevel(LOG_LEVEL)
    logger.addHandler(WestLogHandler())
    cfg = cached_runner_config(build_dir, cache)
    _override_config_from_namespace(cfg, args)

    # Runner creation, phase 3.
    #
    # - Pull out cached runner arguments, and append command-line
    #   values (which should override the cache)
    # - Construct a runner-specific argument parser to handle cached
    #   values plus overrides given in runner_args
    # - Parse arguments and create runner instance from final
    #   RunnerConfig and parsed arguments.

    cached_runner_args = cache.get_list('ZEPHYR_RUNNER_ARGS_{}'.format(
        cmake.make_c_identifier(runner)))
    assert isinstance(runner_args, list), runner_args
    # If the user passed -- to force the parent argument parser to stop
    # parsing, it will show up here, and needs to be filtered out.
    runner_args = [arg for arg in runner_args if arg != '--']
    final_runner_args = cached_runner_args + runner_args
    parser = argparse.ArgumentParser(prog=runner)
    runner_cls.add_parser(parser)
    parsed_args, unknown = parser.parse_known_args(args=final_runner_args)
    if unknown:
        log.die('Runner', runner, 'received unknown arguments:', unknown)
    runner = runner_cls.create(cfg, parsed_args)
    try:
        runner.run(command_name)
    except ValueError as ve:
        log.err(str(ve), fatal=True)
        dump_traceback()
        raise CommandError(1)
    except MissingProgram as e:
        log.die('required program', e.filename,
                'not found; install it or add its location to PATH')